I have an album that has images. I'm having a problem with doing the search function. I want to search for photos with the following caption. Here's what I did so far.
Albums table:
| id | album_name | sort |
|----|------------|------|
| 1 | album_1 | 3 |
| 2 | album_2 | 2 |
| 3 | album_3 | 1 |
Photos table:
| id | album_id | name | sort |
|----|----------|-------|------|
| 1 | 1 | name1 | 1 |
| 2 | 1 | name2 | 2 |
| 3 | 2 | name3 | 3 |
and the following relations on my models:
Photo.php
public function album()
{
return $this->belongsTo(Album::class);
}
Album.php
public function images()
{
return $this->hasMany(Photo::class, 'album_id', 'id)->orderBy('sort');
}
GalleryController.php
public function index(Request $request)
{
$photos = Album::has('images')->orderBy('sort')->with('images')->get();
}
if (!empty($request->search)) {
$photos = Album::whereHas('images', function($query) use ($request) {
$query->where('name', 'like', '%' . $request->search . '%');
})->with('images')->get();
The search function works but if I search for a specific image within the album it returns all of the images in that album.
It's not very pretty, but this is basically what you want.
I've commented the code to explain it.
if (!empty($request->search)) {
$queryString = '%' . $request->search . '%';
$queryClosure = function ($query) use ($queryString) {
$query->where('name', 'LIKE', $queryString);
};
// Get only albums that have images that match the query string.
// This will filter the albums, not the images.
$photos = Album::whereHas('images', $queryClosure)
// Now filter the images of those albums.
->with(['images' => $queryClosure])
// Return the collection.
->get();
}
Edit:
I have updated the answer to use Tim Lewis's suggestion from the comments.
Since the closure is repeated for both steps, we can store it in a variable to keep the code DRY.
Related
I have two tables, school_users and users. I need to create a query, using Eloquent, that gets all users where user_id equal school_id.
so the result must be more than one user, so that also I need to group the result by school_id
thank you in davance
Relations:
User Model:
public function school()
{
return $this->hasMany(SchoolUser::class);
}
SchoolUser Model:
public function user()
{
return $this->hasMany(User::class);
}
School_users table:
+----+---------+------------+-------------+
| id | user_id | school_id | created_at |
+----+---------+------------+-------------+
| 1 | 79 | 79 | <SOME TIME> |
| 2 | 85 | 79 | <SOME TIME> |
| 3 | 86 | 85 | <SOME TIME> |
| 4 | 87 | 85 | <SOME TIME> |
+----+---------+------------+-------------+
users table:
+----+
| id |
+----+-
| 79 |
| 85 |
| 86 |
| 87 |
+----+-
User Model:
public function getUsers()
{
return $this
->leftJoin('school_users', $this->table . '.id', '=', 'school_users.school_id')
->select(
$this->table . '.*',
'school_users.school_id as school_id'
)
->whereIn('users.id', '=', 'school_users.school_id')
->orderBy('id', 'desc')
->get();
}
Use whereColumn to filter user_id equal to school_id,
and use join instead of leftjoin:
public function getUsers()
{
return $this
->join('school_users', function($join) {
$join->on('school_users.user_id', '=', $this->table.'.id')
->whereColumn('school_users.user_id', 'school_users.school_id');
})
->select
(
$this->table.'.*',
'school_users.school_id as school_id'
)
->orderBy($this->table.'.id','desc')
->get();
}
Laravel 5.1.11
I have a simple search in my shop:
public function search($request $request)
{
return Catalog::where('title', 'like', '%'.$request->searchQuery.'%')
->orderBy('id', 'desc')
->paginate(50);
}
This is worked!
But people are looking for goods so: Pump BOSCH. And search result is null.
Because I changed my select:
public function search($request $request)
{
$searchQ = preg_split('/\s+/', $request->searchQuery, -1, PREG_SPLIT_NO_EMPTY);
return Catalog::where(function ($q) use ($searchQ) {
foreach ($searchQ as $value) {
$q->orWhere('title', 'like', "%{$value}%");
}
})
->orderBy('id', 'desc')
->paginate(50);
}
And this is worked), and show all Pumps!
But i want show only one Pump bosch.
My DB table manufactories:
| id | title |
| :--: | :----- |
| 1 | AlKO |
| 2 | BOSCH |
AND catalogs, where m_id is id from table manufactory:
| id | m_id | title | url |
| :--: | :---: | :---- | :--------- |
| 1 | 1 | pump | pump-alko |
| 2 | 2 | pump | pump-bosch |
How do I change the MySQL search query (adding LEFT JOIN and CONCAT) to find Pump bosch?
To make it look like this: CONCAT('catalogs.title', ' ', 'manufactories.title') LIKE '%'.$request->searchQuery.'%'
You can do simply like this,
$data = DB::table('manufactories')
->join('catalogs','manufactories.id','=','catalogs.m_id')
->select('manufactories.title','catalogs.title')
->where(DB::raw('CONCAT(manufactories.title," ",catalogs.title)'), 'like',"%{$value}%")
->get();
I hope it helps,
You can use the Query Builder to do joins e.g.
DB::table('catalogs')
->select('catalogs.*')
->join('manufactories', 'catalogs.m_id', '=', 'manufactories.id', 'left')
->where(function($q) use ($searchQ) {
foreach ($searchQ as $value) {
$q->orWhere('manufactories.title', 'like', "%{$value}%");
$q->orWhere('catalogs.title', 'like', "%{$value}%");
}
})
->get();
For an online competition with the goal of photographing certain objects I've got users uploading pictures of objects, where the objects have a category and a subcategory.
A user's dashboard should look something like this:
------------------------------------------------
| Category |
------------------------------------------------
| ----------------------------------------- |
| | Subcat. | Subcat. | |
| |------------------|--------------------| |
| |Object1 | Object2 | Object1 | Object2 | |
| |------------------|--------------------| |
| | Pic1 | Pic1 | Pic1 | Pic1 | |
| | Pic2 | Pic2 | Pic2 | Pic2 | |
| ---------------------------------------- |
| |
------------------------------------------------
In order to be able to output the pictures in the appropriate loop, I installed hasMany relationships between the models. So I can get an object with a convenient hierarchy by
$userPics = Category::with(['subcats','subcats.objects','subcats.objects.pics'])->get();
QUESTION:
For the dashboard of course I only want the images from a certain user: the Pictures model contains a user_id field. I could get the user's pictures directly: Pictures::where('user_id',$user->id)->get();, but then I don't have the structure in the object to create the desired view shown above.
How can I do something like this:
$userPics = Category::with([...])->where('user_id',$user->id)->get();
Many thanks for any tips!
You want to get categories with pictures that belong to specified user, so you do this (a bit verbose):
Category::with(['subcats', 'subcats.objects' => function ($q) use ($user) {
$q->with(['pictures' => function ($q) use ($user) {
$q->where('user_id', $user->id);
}]);
}])
->whereHas('subcats', function ($q) use ($user) {
$q->whereHas('objects', function ($q) use ($user) {
$q->whereHas('pictures', function ($q) use ($user) {
$q->where('user_id', $user->id);
});
});
})
->get();
You need to use nested with() closures here, because you can load more than two levels of relationship with using dot notation.
If you don't need to load pictures and subcategories data, just remove with() part.
If you also want to filter subcategories, add a closure to with() for subcats.
I need to show feeds with total comments, and total likes on that feed with the detail of users who have commented.
Feeds Table
| id | movie_id | user_id | description |
|----|----------|----------|-------------|
| 1 | 1 | 1 | Lorem Ipsum |
Comments Table
| id | feed_id | user_id | comment |
|----|-------- |----------|-----------|
| 1 | 1 | 2 | comment 1 |
| 2 | 1 | 3 | comment 2 |
Likes Table
| id | feed_id | user_id |
|----|-------- |----------|
| 1 | 1 | 2 |
| 2 | 1 | 3 |
Users Table
| id | username| email |
|----|-------- |--------|
| 1 | a | a#a.com|
| 2 | b | b#b.com|
| 3 | c | c#c.com|
Relations
Feed.php
public function user () {
return $this->belongsTo('App\User');
}
public function likes () {
return $this->hasMany('App\Like');
}
public function comments () {
return $this->hasMany('App\Comment');
}
User.php
public function feeds () {
return $this->belongsToMany('App\Feed');
}
public function like () {
return $this->belongsTo('App\Like');
}
public function comment () {
return $this->belongsTo('App\Comment');
}
Like.php
public function user () {
return $this->belongsTo('App\User');
}
public function feed () {
return $this->belongsTo('App\Feed');
}
Comment.php
public function user () {
return $this->belongsTo('App\User');
}
public function feed () {
return $this->belongsTo('App\Feed');
}
Now I need to fetch all feeds (I have done with this), with comments count, likes count, and users details who have commented.
Ho can I get that in single query using Eloquent.
Try this
$commentsCount = \App\Models\Comment::select('feed_id',\DB::raw('count(id) as comments_count'))->groupBy('feed_id')->toSql();
$likesCount = \App\Models\Like::select('feed_id',\DB::raw('count(id) as likes_count'))->groupBy('feed_id')->toSql();
$records = \DB::table('feeds as f')
->leftJoin('comments as c','f.id','=','c.feed_id')
->leftJoin('users as u','c.user_id','=','u.id')
->leftJoin(\DB::raw('('.$commentsCount.') as k'),'f.id','=','k.feed_id')
->leftJoin(\DB::raw('('.$likesCount.') as l'),'f.id','=','l.feed_id')
->select('f.id as fid','f.description','u.id as uid','u.name','u.email','k.comments_count','l.likes_count')
->orderBy('fid')
->get();
$transform = function(array $records){
$records = collect($records)->groupBy('fid');
return $records->transform(function($items){
$feed['id'] = $items->first()->fid;
$feed['description'] = $items->first()->description;
$feed['count'] = [
'likes' => is_null($items->first()->likes_count) ? 0 : $items->first()->likes_count,
'comments' => is_null($items->first()->comments_count) ? 0 : $items->first()->comments_count,
];
$feed['users'] = $items->transform(function($user){
return is_null($user->uid) ? [] : ['id'=>$user->uid,'name'=>$user->name,'email'=>$user->email];
});
return $feed;
});
};
return array_values($transform($records)->toArray());
you can swap the closure function with other function. like
$this->transform($records);
You can simply access all those properties through the functions defined.
Example:
$feed = Feed::find($id);
foreach($feed->likes() as $like){
echo $like->user()->get('username');
}
And so forth. Up to a point when you call ->get(), you are accessing an object, which can traverse all of these.
I have two tables, posts and likes. I need to create a query, using Eloquent, that gets all posts that have been liked by a specific user_id.
In other words, it should be something like this:
SELECT * FROM posts p LEFT JOIN likes l ON p.id = l.post_id WHERE l.user_id = 2 ORDER BY l.created_at DESC
posts table:
+----+---------+------------+-------------+
| id | user_id | message | created_at |
+----+---------+------------+-------------+
| 1 | 2 | Hello! | <SOME TIME> |
| 2 | 3 | World! | <SOME TIME> |
| 3 | 2 | Something. | <SOME TIME> |
| 4 | 2 | Another. | <SOME TIME> |
+----+---------+------------+-------------+
likes table:
+----+---------+---------+-------------+
| id | post_id | user_id | created_at |
+----+---------+---------+-------------+
| 1 | 1 | 2 | <SOME TIME> |
| 2 | 2 | 2 | <SOME TIME> |
| 3 | 1 | 3 | <SOME TIME> |
| 4 | 3 | 2 | <SOME TIME> |
+----+---------+---------+-------------+
Here is my Postclass:
<?php
class Post extends Eloquent {
protected $table = 'posts';
public function likes()
{
return $this->hasMany('Like');
}
}
And the Like class:
<?php
class Like extends Eloquent {
protected $table = 'likes';
public function post()
{
return $this->belongsTo('Post');
}
}
How can I do this?
This should work:
$userId = //however you get the userid here.
$posts = Post::whereHas('likes', function ($q) use ($userId) {
$q->where('user_id', $user_id);
})->get();
You can use Laravel's DB class to perform joins on two or more tables, following is how your query will be executed in laravel:
$users = DB::table('posts')
->leftJoin('likes', 'posts.id', '=', 'likes.post_id')
->select('posts.*', 'likes.*')
->where('likes.user_id', '=', '2')
->orderBy('likes.created_at', 'desc')
->get();
Don't forget to use DB class on the top of your controller;
If you want to do it with eloquent, you should do the follwing:
$result = Post::whereHas('likes', function ($q) use($user_id)
{
$q->where('user_id', $user_id);
})
->orderBy('likes.created_at')
->get();