Laravel eloquent merge two results and sort - php

I have found tons of posts about this issue and yet no solution work.
Maybe its because of my laravel version. Its 5.7.
I have two results, which look like this:
result_a = DB::connection('mysql_live')->table('user_chatmessages')
->where('from_user', $data->chat_from_user)->get();
$result_b = DB::connection('mysql_live')->table('user_chatmessages')
->where('to_user', $data->chat_from_user)->get();
Now I merge them, which works great:
$merged = $result_a->merge($result_b);
$result = $merged->values()->sortByDesc('date_added');
The sorting does not affect the whole result. The problem is that the sorting sorts first result_a and then result_b.
I tried tons of different syntax variants:
$result = $result_a->merge($result_b)->sortBy('date_added');
$merged = $result_a->merge($result_b);
$result = $merged->sortByDesc('date_added');
$merged = $result_a->merge($result_b)->sortByDesc('date_added');
$result = $merged->all();
$result = ($result_a->merge($result_b))->sortBy('date_added');
Probably even more, I am sitting for quite some time on this issue already and all I find are threads where it looks super simple and people tell it works.
I also tried to sort by ID with the same results.
EDIT
The alternative solution provided by #N69S works for the case if you want to get all received and sent messages of a certain user.
But how do you get the messages between two specific users using the same approach? For example I want to get the chatmessages between the user with ID 1 and the user with ID 2 this will not work:
$result = DB::connection('mysql_live')
->table('user_chatmessages')
->where('from_user', $data->chat_from_user)
->where('to_user', $data->chat_to_user)
->orWhere('from_user', $data->chat_to_user)
->orWhere('to_user', $data->chat_from_user)
->orderBy('date_added', 'desc')
->get();
What I am trying right now looks like this:
$result = DB::connection('mysql_live')->table('user_chatmessages')
->where(function ($query) use ($from, $to) {
$query->where('from_user', $from)->where('to_user', $to);
})->orWhere(function ($query) {
$query->where('from_user', $to)->where('to_user', $from);
})->orderBy('date_added', 'asc')->get();
But I get an error: from & to are not defined.
This works perfectly:
$result = DB::connection('mysql_live')->table('user_chatmessages')
->where(function ($query) {
$query->where('from_user', '1')->where('to_user', '2');
})->orWhere(function ($query) {
$query->where('from_user', '2')->where('to_user', '1');
})->orderBy('date_added', 'asc')->get();

Why dont you recover all the results in one query ?
result_a = DB::connection('mysql_live')
->table('user_chatmessages')
->where('from_user', $data->chat_from_user)
->orWhere('to_user', $data->chat_from_user)
->orderBy('date_added', 'desc')
->get();
or user ->orderBy('created_at', 'desc') if you have the default timestamps fields
EDIT
For recovering the chat between two specific users, you need to make use of the parenthesis.
result_a = DB::connection('mysql_live')
->table('user_chatmessages')
->where(function($query) use($data) {
$query->where('from_user', $data->chat_from_user)
->where('to_user', $data->chat_to_user);
})
->orWhere(function($query) use($data) {
$query->where('to_user', $data->chat_from_user)
->where('from_user', $data->chat_to_user);
})
->orderBy('date_added', 'desc')
->get();

you can get the data directly without using merging like this:
result = DB::connection('mysql_live')
->table('user_chatmessages')
->where(function($query) use ($data){
$query->where('from_user', $data->chat_from_user)->orWhere('to_user', $data->chat_from_user)
})->orderBy('date_added','desc')
->get();

If you wan to use two queries then you can use union.
Sub query
$subQuery = DB::connection('mysql_live')
->table('user_chatmessages')
->where('from_user', $data->chat_from_user);
Add sub query by using union on main query
$results = DB::connection('mysql_live')
->table('user_chatmessages')
->where('to_user', $data->chat_from_user)
->union($subQuery) //see
->orderBy('date_added', 'desc') //see
->get();
This should work. You can use what ever queries just make union of them to avoid merge in collections and then sort by date_added

Related

Trending query Laravel

Right now I have a subquery to get the count of payments for the current month and then getting the 4 products with the highest payment_count. This query works fine but I'm wondering if there's a more simple way to do the same since its getting difficult to read.
$latestPayments = DB::table('payments')
->select('product_id', DB::raw('COUNT(*) as payments_count'))
->whereMonth('created_at', Carbon::now()->month)
->groupBy('product_id');
$trendingProducts = DB::table('products')
->joinSub($latestPayments, 'latest_payments', function ($join) {
$join->on('products.id', '=', 'latest_payments.product_id');
})->orderBy('payments_count', 'DESC')->take(4)->get();
This did it!
$trendingProducts = Product::withCount(['payments' => function($query) {
$query->whereMonth('created_at', Carbon::now()->month);
}])->orderBy('payments_count', 'DESC')->take(4)->get();
If you are using eloquent query with relational database you can do like this:
$latestPaymentWithTrendingProduct = App\Payment::with(['products', function($product) {
$product->orderBy('payments_count', 'DESC')->take(4);
}])->whereMonth('created_at', date('m'))->get()->groupBy('product_id');
This will lessen the code but still do the same thing.

How to fix whereNotExists and where query builder laravel

I try to combine whereNotExists and where, if you use it simultaneously it will and if you try one of them you can
$query = DB::table('tabel_produk')->where('kode_customer',$cust)->whereNotExists(function($query){
$query->select(DB::raw(1))->from('tabel_detail_realisasi')->whereRaw('tabel_detail_realisasi.barcode = tabel_produk.barcode');
})->distinct()->orderBy('barcode','asc') ->get();
Pleae help me with this
I don't have your DB schema so I've tried something similar with a local DB I have and it seems to be working fine. See my example below. Could you please replace my query with yours and see what's output by the query logger?
DB::flushQueryLog();
DB::enableQueryLog();
$results = DB::table('product_templates')
//Non deleted products
->where('deleted', '=', '0')
//
->whereNotExists(function ($query) {
//Where the category is not 'General'
$query
->select(DB::raw(1))
->from('product_categories')
->whereRaw('product_categories.id = product_templates.category_id')
->where('product_categories.name', 'General');
})
->distinct()
->orderBy('name', 'asc')->get();
DB::disableQueryLog();
$queryLog = DB::getQueryLog();
logger("Query results", compact('results', 'queryLog'));

How do you filter the user with hasRole() in Laravel 5 within relational query?

I want to filter my query and return only if the user hasRole "Premium" and limit the result to 10.
Along with this query is a count of records which Conversion has and sort it in DESC order by total column.
Right now I have a working query that returns the count of Conversion and with a User but without user filter Role.
// Model Conversion belongs to User
// $from & $end uses Carbon::createDate()
// Current code
$query = Conversion::select('user_id',DB::raw('COUNT(*) as total'))
->whereBetween('created_at', [$from,$end])
->where('type','code')
->where('action','generate')
->whereNotNull('parent_id')
->with('user')
->groupBy('user_id')
->orderBy('total', 'DESC')
->take(10)
->get();
// current result
foreach ($query as $q) {
$q->user->name; // To access user's name
$q->total; // To access total count
}
// I tried this but no luck
$query = Conversion::select('user_id',DB::raw('COUNT(*) as total'))
->whereBetween('created_at', [$from,$end])
->where('type','code')
->where('action','generate')
->whereNotNull('parent_id')
->with('user', function($q) {
$q->hasRole('Premium');
})
->groupBy('user_id')
->orderBy('total', 'DESC')
->take(10)
->get();
You need to use whereHas instead of with, like this:
->whereHas('user', function ($query) {
$query->where('role','Premium');
})
Use the whereHas() instead of with(). Also, you can't use hasRole() if it's not a local scope:
->whereHas('user.roles', function($q) {
$q->where('name', 'Premium');
})

how to handle Multiple Orwhere in Laravel

I'm working in Laravel 5 and am using the Orwhere clausule, my code to consult is this:
$estudiantes= Usuario::
where('rol', '=', 'ESTUDIANTE')
->whereHas('perfil', function($query) use ($data){
if($data!="")
$query->Where('doc_identidad', '=' ,$data)
->orWhere('nombres','like','%'.$data.'%')
->orWhere('apellidos','like','%'.$data.'%');
dd($query);
})->get();
So, I want to filter every Usuario with rol ESTUDIANTE that works very fine, then I want to filter which of these have doc_identidad or nombres or apellidos like you see, I have a dd($query) to see the tree of the query, and I noticed that the first where uses and instead of or. This is the tree:
So, I have the next:
where1 and where2 or where3 or where4
and I want:
where1 and (where2 or where3 or where4)
so, how should I do it? thanks!
where1(a=1) and (where2(b=1) or where3(c=1) or where4(d=1))
Model::where(function ($query) {
$query->where('a', '=', 1);
})->where(function ($query) {
$query->where('b', '=', 1)
->orWhere('c', '=', 1)
->orWhere('d', '=', 1);
});

Laravel OrderBy Relationship count with pagination

I have many projects and each has many orders, some completed, some not.
I want to order them by the amount of completed orders like this:
$products = $products->orderBy(function($product) {
return $product->orders->where('status', 2)->count();
})->paginate(15);
I know the order call doesn't work like this but this is the best was show the problem. SortBy doesn't work because I want to use pagination.
Finally found a good solution for the problem:
$products = $products->join('orders', function ($join) {
$join->on('orders.product_id', '=', 'products.id')
->where('orders.status', '=', 2);
})
->groupBy('products.id')
->orderBy('count', $order)
->select((['products.*', DB::raw('COUNT(orders.product_id) as count')]))->paginate(50);
Try this if it works:
$categories = Prodcuts::with(array('orders' => function($query) {
$query->select(DB::raw('SELECT * count(status) WHERE status = 2 as count'))
$query->orderBy('MAX(count)')
}))->paginate(15);
return View::make('products.index', compact('categories'));
Note: This is not tested.
From 5.2 on wards you can use the withCount for counting relationship result.
In this case the
$products = $products->withCount(['orders' => function ($query) {
$query->where('status', 2);
}]);
Reference : https://laravel.com/docs/5.2/eloquent-relationships

Categories