In my application, there are article and news tables. I know I can search for matching title in news table or article,
just by doing something like:
$query = $request['search'];
$searchResult= DB::table('article')->where('title', 'LIKE', '%$query%')
->orderBy('created_at', 'desc')->paginate(10);
or
$searchResult= DB::table('news')->where('title', 'LIKE', '%$query%')
->orderBy('created_at', 'desc')->paginate(10);
but what I want to do is to search both of them and return some information about them alongside what the reuslt type is, in terms of news and article. And than orther them by created_at as if they were in the same table.
Laravel 5.4
You can do that if getting 10 news and 10 articles per page is what you want. But in this case, you'll need to manually create paginator.
Load the data:
$articles = DB::table('article')
->where('title', 'like', '%$query%')
->latest()
->skip(0)
->take(10)
->get();
$news = DB::table('news')
->where('title', 'like', '%$query%')
->latest()
->skip(0)
->take(10)
->get();
Then merge the results:
$merged = $articles->merge($news);
Then order by date if you need to:
$merged = $merge->sortByDesc('created_at');
Related
On my website, users can post images.
Images can have tags.
There's 4 tables for this, the images table, the images_tag pivot table, the tag table, and of course the users table.
A user can have multiple images with the same tag(s).
I can pull up the tags a user has used across all his images with this query:
$userTags = Tag::whereHas('images', function($q) use($user) {
$q->where('created_by', $user->id);
})->get();
However, I want to make it so that I can order these tags based on how frequently a user uses them. In other words, I want to order by duplicates. Is this possible?
To achieve this, you're going to need to join the images_tags and images tables, count the number of tags, and order by those tags.
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->get();
The above query will only work in MySQL if the only_full_group_by option is disabled. Otherwise, you're going to need to either rewrite this to use a sub query, or do the ordering in the returned Laravel Collection. For example:
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->get();
$tags = $tags->sortByDesc(function ($tag) {
return $tag->total;
});
If you want to add this to your user model, per your comment, create a function similar to the following:
public function getMostUsedTags($limit = 3)
{
return Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $this->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->limit($limit)
->get();
}
I have a table named records with a user_id column which links to a users table to set ownership.
I can correctly filter the records by title with a search string:
$records->where('title', 'LIKE', '%'.$search.'%');
But I'd like to return also the results containing the users.firstname and users.lastname, this is my (awful) join attempt:
$records->join('users', 'users.id', '=', 'records.user_id')
->where('users.firstname', 'LIKE', '%'.$search.'%')
->orWhere('users.lastname', 'LIKE', '%'.$search.'%')
->orWhere('title', 'LIKE', '%'.$search.'%');
// SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in order clause is ambiguous
While I wait for a better answer I found a solution which works but it's not optimal since it involves one extra query to gather the author user_id and use it subsequently to query the records:
// Get the author ID
$author = DB::table('users')
->select(DB::raw('CONCAT_WS(" ",`firstname`,`lastname`) as `fullname`,id'))
->having('fullname', 'LIKE', '%'.$search.'%')
->first();
// $author output:
stdClass Object
(
[fullname] => John Doe
[id] => 35
)
// Query the records using the gathered ID
$records->where('user_id', $author->id)
->orWhere('title', 'LIKE', '%'.$search.'%');
Problems with this solution: Apart from the extra query, if somebody searches for John Doe or Some Title the results are correct. But if searching for John Doe Some Title, nothing is shown because the author and the title can't be found.
You need to set that also use the search parameter in your inner query:
$records->join('users', function($join) use ($search)
{
$join->on('users.id', '=', 'records.user_id')
->where('users.firstname', 'LIKE', '%'.$search.'%')
->orWhere('users.lastname', 'LIKE', '%'.$search.'%');
});
If I understand you want to return result from Records by filtering with $search and also want to show users info for this records.
You can use Eloquent.
Your model must be:
In User model:
public function records()
{
return $this->hasMany(Record::class);
}
In Record model:
public function user()
{
return $this->belongsTo(User::class);
}
And in Controller:
Record::where('title', 'LIKE', '%'.$search.'%')
->with('user')
->first();
I'm struggling to get unique results when using the DISTINCT method in laravel. This is my query
//Get users that are part of this sector
$users = DB::table('users')->distinct()
->join('projects', 'users.id', '=', 'projects.userID')
->where('projects.sectorID', '=', $sector->sectorID)
->get();
dd($users);
The result shows 3 users with the same ID, when I only want one of them in the results.
How should I change my query?
Try to use group by id
$users = DB::table('users')
->join('projects', 'users.id', '=', 'projects.userID')
->where('projects.sectorID', '=', $sector->sectorID)
->groupBy('users.id')
->get();
dd($users);
My original query searched the motherboards, then found images for the motherboards. But now, some of the motherboards do not have any image associated so I want to run one query that can find 20 unique motherboards with images.
Code so far:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->where('images.item_type', '=', 'motherboard')
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();
I have even tried selecting specific results:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->select('motherboards.motherboard_id', 'motherboards.name')
->where('images.item_type', '=', 'motherboard')
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();
The problem with the code above is that when I loop through each $newMotherboards, it has duplicates for every image that exists with its ID. I only want to retrieve 20 unique motherboards where they were added the most recently, but have images.
If an item has 5 images and it is one of the recent 20 added, then it will appear five times of my 20 limit.
Distinct version:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->select('motherboards.motherboard_id', 'motherboards.name')
->where('images.item_type', '=', 'motherboard')
->distinct()
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();
Groupby version:
$newMotherboards = Motherboards::join('images', 'motherboards.motherboard_id', '=', 'images.item_id')
->select('motherboards.motherboard_id', 'motherboards.name')
->where('images.item_type', '=', 'motherboard')
->groupby('images.item_type')
->orderBy('motherboards.date_added', 'desc')
->take(20)
->get();
I have a table customers and a table orders.
And I want to make an ajax call to get a list of all customers with name x and their orders.
I got the ajax function and my function to retrieve the customer looks like this:
$customers = Customer::where('first_name', 'LIKE', '%'.$name.'%')
->orWhere('last_name', 'LIKE', '%'.$name.'%')
->where('user_id', Auth::user()->id)
->get()
->toJson();
return $customers;
With this I can only get all customers, can I modify this to get also their orders?
I think I could do it with join or is there any magic function?
Thanks
You can use relationship: follow the link and create one to many relationship and use the relationship in your query.
http://laravel.com/docs/eloquent#relationships
$customers = Customer::with('orders')
->where('first_name', 'LIKE', '%'.$name.'%')
->orWhere('last_name', 'LIKE', '%'.$name.'%')
->where('user_id', Auth::user()->id)
->get();
return $customers->toJson();