I have Call model. Each call has Theme. How i did this:
class Call extends Model
{
// some code here
public function theme()
{
return $this->hasOne(Theme::class, 'id', 'theme_id')->withTrashed();
}
// some code there
}
This works great. What i want to do is get count of each themes used in all calls.
There is 200 calls for example. 100 of them has theme_id=3, 50 of them has 6, and last 50 has 8. I want to get result like:
{
{theme_id:3, themes_count=100},
{theme_id:6, themes_count=50},
{theme_id:8, themes_count=50},
}
How to do that?
\DB::select("select theme_id, count(*) themes_count from calls group by theme_id");
Or using QueryBuilder:
Call::selectRaw("count(*) themes_count, theme_id")
->groupBy("theme_id")
->get();
In eloquent query builder:
$collection = Theme::groupBy('theme_id')
->selectRaw('theme_id, count(*) as themes_count')
->get();
Related
So i have a pivot table like the following :
match id
player id
score
And i want to query to get the number of wins/losses for a given user id. (wins based on user id with the highest score for a game)
In sql i would write this like :
SELECT user_id, score
from match_user matchu1
where score = (select max(score) from match_user matchu2 where matchu1.match_id = matchu2.match_id)
How would i express this query in laravel, or is there a better method of doing this that i am missing ?
There are multiple ways to achieve this. The easiest and cleaniest way to me is defining
a relationship with pivot.
class Match extends Model
{
public function players()
{
return $this->belongsToMany(User::class, 'match_user')->withPivot('score');
}
public function winner()
{
return $this->players
->sortByDesc(function ($player) {
return $player->pivot->score;
})
->first();
}
}
Then you can simply get the winner by saying:
$match->winner();
This is to answer your true intention of asking this question, which is to get the number of wins for a single user, as you commented on my answer. The following the the best solution that I can think of for now:
class Match extends Model
{
public function scopeWonBy($query, User $user)
{
return $query->selectRaw('matches.id, max(match_user.score) AS max_store, match_user.player_id AS player_id')
->join('match_user', 'matches.id', '=', 'match_user.match_id')
->groupBy('matches.id')
->having('player_id', $user->id);
}
}
Later on, you can say:
$matches = Match::wonBy($user);
$count = Match::wonBy($user)->count();
I'm not going to write your query for you as I don't want to provide an untested solution but the following code example should give you a good idea of how to implement subqueries with the query builder.
$q->where('price_date', function($q) use ($start_date)
{
$q->from('benchmarks_table_name')
->selectRaw('min(price_date)')
->where('price_date', '>=', $start_date)
->where('ticker', $this->ticker);
});
I have a mysql query like this:
select result.*, rank_text.text
from cache_user_challenge_result result
left join rank_text on result.rank
between rank_text.rank_from and rank_text.rank_to
Now I want to change this to eloquent for my laravel project, I tried this but it's not work:
$this->select(
"{$this->table}.user_id",
'rank_text.text'
)
->leftJoin('rank_text', "{$this->table}.rank")
->whereBetween("{$this->table}.rank", ['rank_text.rankFrom', 'rank_text.rankTo'])
->first();
Can you tell me what's wrong with this?
Thank you very much!
Update:
After a lot of hours, I change my query to this:
$this->select(
"{$this->table}.user_id",
'rank_text.text'
)
->leftJoin('rank_text', function($query) {
$query->whereBetween("{$this->table}.rank", ['rank_text.rank_from', 'rank_text.rank_to']);
})
->get();
But it's only can get user_id, not the text.
Try to create cache_user_challenge_result model Like
class CacheUserChallengeResult extends Model {
protected $table = 'cache_user_challenge_result';
public function scopeGetCacheUserRank()
{
return static::select(DB::raw('cache_user_challenge_result.*,rank_text.text'))->leftJoin('rank_text', function($join) {
$join->on('cache_user_challenge_result..rank', '=', 'rank_text.rank')->whereBetween('cache_user_challenge_result.rank',['rank_text.rankFrom', 'rank_text.rankTo']);
});
}
}
In Controller You can call like this
CacheUserChallengeResult::getCacheUserRank()->get();
It will provide you the collection for the rank you desire, also you can pass param for which rank you want in range
Is there any way to get relational data ( one to many relation records ) using joins in laravel without creating different records in collection :
Example:
$orders = DB::table('orders')
->join('users', 'users.id', '=', 'orders.users_id')
->join('order_items', 'order_items.order_id', '=', 'orders.id')
->select('users.*', 'order_items.*')
->get();
So here what's happening is that its creating 6 records if order has 6 items but i want something like single records in which it has array or collection where are order items are listed.
Output I want is generally of this order:
Collection {# ▼
#items: array:[▼
0 => {
+'id':1,
...,
+ 'items: [
//here i want all the records of relation order items
]
}
]
}
Is there any way to achieve this result without using with() or load() and just only with joins or raw queries?
You should try this:
$orders = DB::table('orders')
->select('users.*', 'order_items.*')
->leftJoin('users', 'users.id', '=', 'orders.users_id')
->leftJoin('order_items', 'order_items.order_id', '=', 'orders.id')
->get();
This answer is speculative, but perhaps you want to report a single row for each user, with a CSV list of order items:
$orders = DB::table('orders AS o')
->join('users AS u', 'u.id', '=', 'o.users_id')
->join('order_items AS oi', 'oi.order_id', '=', 'o.id')
->select('u.id', DB::raw('GROUP_CONCAT(oi.name) AS orders'))
->groupBy('u.id')
->get();
If there's no reason stopping you from using the Eloquent, is the best way for working with databases.
The Eloquent ORM included with Laravel provides a beautiful, simple
ActiveRecord implementation for working with your database
Here is the Documentation Eloquent: Getting Started
The model relationship made easy in laravel, you can get you want as following:
The User model relationships:
//user orders
public function orders() {
return $this->hasMany('App\Order');
}
The Order model relationships:
//order items
public function items() {
return $this->hasMany('App\OrderItem');
}
//order owner
public function user() {
return $this->belongsTo('App\User');
}
The OrderItem model relationships:
//order
public function order() {
return $this->belongsTo('App\Order');
}
Here is a quick example of how you may get the order's items
$orders = User::find($id)->orders
foreach($orders as $order) {
$orderItems = $order->items;
}
you can make the collection the way you prefer, but strongly recommend using Eloquent Resources, since most apps these days expecting JSON responses.
I have an issue with ordering model by it's relationship's latest object field.
I have a class named Coin that is related to DailyPrices, that 1 coin can have many DailyPrices. I want to sort coins by latest DailyPrices field named vol.
I tried doing
$coins = Coin::join('daily_prices', 'daily_prices.coin_id', '=', 'coins.id')
->orderBy('daily_prices.vol', 'desc')
->paginate(100);
and many variations about it, but I can't get it to work. What am I doing wrong?
why don't you use created_at instead of vol
$coins = Coin::join('daily_prices', 'daily_prices.coin_id', '=', 'coins.id')->order_by('created_at', 'desc')->paginate(100);
You can do with creating two separate model for coin and daily price.
class Coin extends Model {
public function dailyPrices(){
return $this->hasMany('App\DailyPrice')->orderBy('vol', 'DESC');
}
}
class DailyPrice extends Model {
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'daily_prices';
/**
* Get the coin that owns the daily price.
*/
public function coin()
{
return $this->belongsTo('App\Coin');
}
}
and call with ID in your controller like this
$coinData = Coin::find($coin_id)->with('dailyPrices')->first();
You made two mistakes in your code:
Condition check
Not select table
Here is a code after making changes:
$order='desc';
Coin::join('daily_prices', 'coins.id', '=', 'daily_prices.coin_id')->orderBy('daily_prices.vol', $order)->select('coins.*')->paginate(100);
You can also see more details from here:Order by on relationship
You can use One to Many relationship :
class Coin {
public function dailyPrices() {
return $this->hasMany(DailyPrice::class);
}
}
DailyPrice :
class DailyPrice {
public function coin() {
return $this->belongsTo(Coin::class);
}
}
Then in your controller :
Coin::with('dailyPrices' => function ($query) {
$query->orderBy('vol', 'desc');
))->paginate(100);
The with function will load dailyPrice relationship on your item and the value argument will execute a query related to the relation loaded (here an order by).
Hopes it helps you.
Maybe the question was unclear, I don't know. But neither of these were relevant to an issue. I have resolved the problem with this query:
SELECT c.* FROM daily_prices AS dp JOIN coins AS c ON dp.coin_id=c.id WHERE dp.id IN (SELECT MAX(id) FROM daily_prices GROUP BY coin_id) ORDER BY vol DESC
and transformed to laravel call:
Coin::join('daily_prices', 'daily_prices.coin_id', '=', 'coins.id')
->whereIn('daily_prices.id', function ($query) {
$query->selectRaw('MAX(id)')
->from('daily_prices')
->groupBy('coin_id');
})
->orderBy('daily_prices.vol', 'desc')
->paginate(100);
I am having a issue here that I am not solving.
I am trying to make a query in Laravel where I need to count how many offers does a business has, to show Business id, Total Offers for a Business and Business Name.
$business_offers = DB::table('offers')
->join('businesses', 'offers.id_business', '=', 'businesses.id')
->select(['businesses.id', 'businesses.name', DB::raw('count(offers.id) as total_offers')])
->orderby('total_offers', 'DESC')
->get();
but it is not working in this way. I have also done the query in mysql but can't integrate it in Laravel.
SELECT bu.id,(SELECT count(of.id) from offers of where of.id_business = bu.id )
as total_offers, bu.`name` from businesses bu ORDER BY total_offers DESC
thanks in advance
Reading it literally something like the following might work:
$business_offers = DB::table('businesses bu')
->select(['bu.id', DB::raw("(SELECT count(of.id) from offers of where of.id_business = bu.id )") ,'bu.name'])
->orderBy('total_offers', 'DESC')
->get();
If you want it a bit more efficient (maybe):
$business_offers = DB::table('offers')
->join('businesses', 'offers.id_business', '=', 'businesses.id')
->select(['businesses.id', DB::raw("COUNT(1) as total_offers"),'businesses.name'])
->groupBy("businesses.id","businesses.name")
->orderBy('total_offers', 'DESC')
->get();
If you have models and relations set up it should be as easy as:
$businesses = Business::withCount(['offers'])->get;
foreach ($businesses as $business) {
echo $business->offers_count;
}
From the Laravel documentation:
If you want to count the number of results from a relationship without
actually loading them you may use the withCount method, which will
place a {relation}_count column on your resulting models.
All you need in your Business model is:
class Business extends Model
{
/**
* Get all of the offers for the business.
*/
public function offers()
{
return $this->hasMany('App\Offer');
}
}
and in the Offer model:
class Offer extends Model
{
/**
* Get the business for the current offer.
*/
public function business()
{
return $this->belongsTo('App\Business', 'business_id');
}
}