Join and OrderBy within with laravel eloquent query - mysql

I want to display ordered list of stores based on cities from a brand.
This is the code I tried
$brand = Brand::where('slug','=',$slugurl)
->with(['stores' => function($q){
$q->where('status', 1)
->join('cities', function ($join){
$join->on('cities.id', '=', 'stores.city_id')->orderBy('cities.sort_number', 'DESC');
});
}])
->firstOrFail();
The relationship of the tables :
Brand hasMany Stores and Stores belongTo Cities
The listings results output is not ordered based on cities sort_number. Any idea how to achieve this ?

It is useless to order in join's closure.
You need to append the orderBy after join:
$brand = Brand::where('slug','=',$slugurl)
->with(['stores' => function($q){
$q->where('status', 1)
->join('cities', 'cities.id', '=', 'stores.city_id')
->orderBy('cities.sort_number', 'DESC');
}])
->firstOrFail();
This query convert to raw sql is:
select * from brands where slug = ? limit 1;
select * from stores
join cities on cities.id = stores.city_id
where status = 1 and stores.brand_id in (?)
order by cities.sort_number desc;

Related

laravel eloquent query with relations

I'm trying to replace a mysql query with laravel eloquent. This is my structure.
Consumers Table
---------------
id, email, name
Transactions Table
-------------------
id, consumer_id, value, bonus_value
Output that I'm trying to achieve
id, email, name, total_value
1, abc#123.com, Al, 11000
2, abc2#123.com, Bl, 200000
This is what I have added in Consumer.php
/**
* Transactions Relationship
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactions(){
return $this->hasMany(Transaction::class, 'consumer_id');
}
And this is the query I've written so far.
$query = Consumer::query()
->join('consumer_transactions AS ct', function($q) {
$q->on('consumers.id', '=', 'ct.consumer_id')
->where('ct.status', 'processed')
->where('ct.approved', 1)
->select(DB::raw('SUM(ct.value + ct.bonus_value) AS total_points'))
;
})
->whereIn('consumers.id', $consumerIds)
->get()
;
It doesn't return total_points
Join Clause that passed to your join take Illuminate\Database\Query\JoinClause witch doesn't have a method called 'select'.
you select should be out of join clause.
$query = Consumer::query()
->join('consumer_transactions AS ct', function($q) {
$q->on('consumers.id', '=', 'ct.consumer_id')
->where('ct.status', 'processed')
->where('ct.approved', 1);
})
->select( ['consumers.*', DB::raw('SUM(ct.value + ct.bonus_value) AS total_points')])
->whereIn('consumers.id', $consumerIds)
->get();
I'm not fun of joining tables. That's why I can offer you a different approach.
$consumers = Consumer::whereIn('id', $consumerIds)
->with(['transactions' => function($query) {
$query
->where('startus', 'processed')
->where('approved', 1)
}])->get()
->map(function($item, $key) {
return $item->total_points = $item->transactions->value + $item->transactions->bonus_value
});

how to run mysql query in Laravel

I want to transform my MySql query into a Query in Laravel but I really don't know how to do this. I don't know how to rename in FROM like in SQL
My query is the following one :
SELECT f2.* FROM formation f2 WHERE f2.theme_id IN
(SELECT f.theme_id FROM user_formation uf JOIN formation f ON uf.formation_id = f.id WHERE uf.user_id = 2)
AND f2.id NOT IN
(SELECT formation_id FROM user_formation WHERE user_id = 2);
I tried something like this but ...
$q = Formation::query()
->from('formation AS f2')
->whereIn('f2.theme_id', function($r)
{
$r->select('f.theme_id')->from('user_formation AS uf')
->join('formation', function($join)
{
$join->on('uf.formation_id', '=', 'f.id')
->where ('uf.user_id', '=', $id)
});
});
->whereNotIn('f2.id', function($s){
$s->select('formation.id')
->from('user_formation')
->where('user_id', '=', $id)
})->get();
thanks for help.
If you want to run this raw query you can run:
$res = DB::select('
SELECT f2.*
FROM formation f2
WHERE f2.theme_id IN
(SELECT f.theme_id FROM user_formation uf JOIN formation f ON uf.formation_id = f.id WHERE uf.user_id = 2)
AND f2.id NOT IN
(SELECT formation_id FROM user_formation WHERE user_id = 2)');
Or you can rewrite this query in laravel query builder Eloquent ORM:
Formations::query()
->whereIn('formations.theme_id', function($q){
$user_formations_table = (new UserFormation)->getTable();
$formation_table = (new Formation)->getTable();
$q->select('paper_type_id')
->from($user_formations_table)
->join($formation_table, "$user_formations_table.formation_id", '=', "$formation_table.id")
->where("$user_formations_table.user_id", 2);
})->whereNotIn('formations.id', function($q){
$user_formations_table = (new UserFormation)->getTable();
$q->select('formation_id')
->where("$user_formations_table.user_id", 2);
})
->get();
Note that I have used models Formations, UserFormation, Formation Because you have used 3 different tables, you should add this models and specify tables to run ORM query
I advice to run first RAW query if there is no another need to run it with Eloquent
Hope this helps you
First of all, you need to fix your code indentations so you don't confuse yourself. Second, you placed semicolon in the wrong places. Third, you need to pass $id inside function because of the variable scope.
$q = Formation::query()
->whereIn('f2.theme_id', function($r) use ($id) {
$r->select('f.theme_id')->from('user_formation AS uf')
->join('formation', function($join) use ($id) {
$join->on('uf.formation_id', '=', 'f.id')
->where('uf.user_id', '=', $id);
}
);
})
->whereNotIn('f2.id', function($s) use ($id) {
$s->select('formation.id')
->from('user_formation')
->where('user_id', '=', $id);
})->get();
Note : If you are using VSCode, I suggest to use PHP Intelephense as it will help with autocomplete, syntax check, etc.

Get top best score in Laravel

I have 2 tables:
user: id, name
score: id, user_id, point
Now I want to get 5 users name who have the best score but seem like it was wrong.
Here's my code:
public function getTop(){
$top = DB::table('score')
->select('user_id', DB::raw('COUNT(point)'))
->groupBy('user_id')
->orderBy(DB::raw('COUNT(point)'), 'DESC')
->take(5)
->get();
return view('home',compact('top'));
}
In your case Database query makes more senses.
Database query to get top 5 user_id with total score.
Join users table with that result.
$topResult = DB::table('users'
)->join(DB::raw('(SELECT user_id, SUM(point) as score FROM score GROUP BY user_id ORDER BY SUM(point) LIMIT 5) as top_scorer'), function($join) {
$join->on('top_scorer.user_id', '=','users.id');
})
->select(['users.*', 'top_scorer.score']) //Select fields you need.
->orderBy('top_scorer.score')
->get();
Try this.
DB::table('users')
->select(['users.id', DB::raw('MAX(sc.point) AS score')])
->join('score AS sc', 'sc.id', '=', 'users.id')
->groupBy('users.id')
->take(5)->get();

Laravel Many to Many How to form query in eloquent or in query builder

From the following query im getting the expected result:
SELECT *
FROM rooms r
JOIN amenities_room am
ON r.id = am.room_id
JOIN amenities a
ON am.amenities_id = a.id
AND a.id IN (2,3)
GROUP BY r.id
HAVING COUNT(*)=2;
How can i for the query in laravel way in (Eloquent or in Query Builder)
Note:
The following tables are involved:
rooms
id
number
name
amenities
id
name
amenities_room
room_id
amenities_id
$rooms = Room::with('amenities')
->withCount('amenities', function($query){
$query->whereIn('id', [2, 3]);
})
->where('amenities_count', 2)
->get()
Docs for counting related models: https://laravel.com/docs/5.5/eloquent-relationships#counting-related-models
You got this error mb_strpos() expects parameter 1 to be string, object given because your eloquent is expecting a string but you have passed an object here in withCount() try this
$rooms = Room::with('amenities')
->withCount('amenities')->where(function($query){
$query->whereIn('id', [2, 3]);
})
->where('amenities_count', 2)
->get()

Which laravel query to use to sort top entries according to related table

I have two models: posts and likes. Posts and likes have one-to-many relationship (so, one post has many likes). Likes model has also an isActive field which shows liking is active or passive.
I want to get (sort) top 5 posts which had received maximum "active" likes (only likes whose isActive field is true would be considered).
Which Laravel query could give me the result?
My question is sorting the post not only according to a field of a related model but also count of entries in the related table.
This is the query:
$posts = Post::selectRaw('posts.*, count(likings.id) as likes_count')
->leftJoin('likings', function ($join) {
$join->on('likings.post_id', '=', 'posts.id')
->where('likings.isActive', '=', 1);
})
->groupBy('posts.id')
->orderBy('likes_count', 'desc')
->take(5)
->get();
And this is the error:
SQLSTATE[42000]: Syntax error or access violation: 1055 'database.posts.user_id' isn't in GROUP BY
(SQL: select posts.*, count(likings.id) as likes_count from 'posts' left join 'likings' on 'likings'.'post_id' = 'posts'.'id' and 'likings'.'isActive' = 1 group by 'posts'.'id' order by 'likes_count' desc limit 5)
or just exequte this query
Post::with(['likes' => function ($query){
$query->where('active', 1);
}]);
and sort it by php if its too hard in mysql. For ex some PostTransformer class
Post::selectRaw('posts.*, count(likes.id) as likes_count')
->leftJoin('likes', function ($join) {
$join->on('likes.post_id', '=', 'posts.id')
->where('likes.is_active', '=', 1);
})
->groupBy('posts.id')
->orderBy('likes_count', 'desc')
->take(5)
->get();
or subselect:
Post::select('*')->selectSub(function ($q) {
$q->from('likes')
->whereRaw('likes.post_id = posts.id')
->where('is_active', 1)
->selectRaw('count(*)');
}, 'likes_count')
->orderBy('likes_count', 'desc')
->take(5)
->get();
Post::join(DB::raw('(select post_id, count(post_id) as number from likes) as likes_count ON posts.id = likes_count.post_id where likes_count.active = 1'), null)->orderBy('likes_count.number', 'desc')->limit(5);
I wrote that without checking this out, so don't hate