How to order by value when i get results in array? - laravel

I get all tags and its look like this :
"testeng" => 0
"testeng1" => 5
So what i want to do is order this by value so that first one is this with value 5. Any suggestion how can i do this?
$tags = ATags::with('articles')->whereHas('language',function($query) use($current_language_id){
$query->where('id','=',$current_language_id);
})->get();
$count_tag = [];
foreach($tags as $tag){
$count_tag[$tag->name] = $tag->articles->count();
}

You can use arsort() as:
arsort($count_tag)
arsort — Sort an array in reverse order and maintain index association
OR
You can use withCount to sort the result directly in query as:
$tags = ATags::with('articles')
->whereHas('language',function($query) use($current_language_id){
$query->where('id','=',$current_language_id);
})
->withCount('articles')
->orderBy('articles_count', 'desc')
->take(5)
->get();
From the docs
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.

You can use Collection's sortBy or sortByDesc & count methods to sort your results like this:
$tags = ATags::with('articles')->whereHas('language',function($query) use($current_language_id) {
$query->where('id','=',$current_language_id);
})
->get()
->sortByDesc(function($tag) { // <---- sorting it via article's count
return $tag->articles->count();
})
->take(5); // <----- fetch largest 5 from collection
You can pass a closure method to sortBy or sortByDesc collection's methods to manipulate your results.

Related

Eloquent query with GroupBy, Sum and Paginator

Hi I am trying to do this query
$collections = Collection::groupBy(['branch_office_id', DB::raw('MONTH(`created_at`)')])->sum('gross_amount')->paginate(10);
But it displays this error:
Call to a member function paginate() on string
So I wonder how can I do thta without to lose the paginate function ? Thanks.
You can sum on each group of the result by mapping the result of the groupBy and do your summation in the map function. In below code, I suppose you have an array in the map and tried to get the summation of the key.
$collections = Collection::groupBy(['branch_office_id', DB::raw('MONTH(`created_at`)')])
->map(function($item){
return array_sum(array_filter($item,function($k=>$v){
return $k=='gross_amount' ? $v : null;
}));
})
->paginate(10);

How to sort Eloquent collection after fetching results?

In my controller I have this query
$query = Market::whereHas('cities', function($query) use ($city) {
$query->where('id', $city);
})->get();
Then I want to make a few operations with this collection and remove my subquerys from the main object
$return['highlighted'] = $markets->where('highlighted', true);
$markets = $markets->diff($return['highlighted']);
The problem is when I try to sort it by created_at
$return['latest'] = $markets->sortByDesc('created_at')->take(4);
$markets = $markets->diff($return['latest']);
It just won't work, keeps returning the first 4 objects order by id, I've tried parsing created_at inside a callback function with Carbon::parse() and strtotime with no results.
I'm avoiding at all cost to make 2 different database querys since the original $markets has all the data that I need.
Any suggestion?
Thanks
I think your problem is you try to sort and take in one-go and also missing a small thing when you try to access the values of the collection.
Try below approach:
$return['latest'] = $markets->sortByDesc('created_at');
$markets = $markets->diff($return['latest']->values()->take(4));
Or you may need to do it like:
$return['latest'] = $markets->sortByDesc('created_at');
$return['latest'] = $return['latest']->values()->take(4);
$markets = $markets->diff($return['latest']->all());

How to use search value contain in array field using eloquent in Laravel

I'm working on laravel array serialize. Below is serialize in controller.
public function CreateSave(CreateTestTopicRequest $request){
...code..
$testtopic->class_room_id = $request->classroom;
$testtopic->roomno = serialize($request->roomno);
...code..
}
Then, roomno will be saved to database like.
a:2:{i:0;s:1:"1";i:1;s:1:"2";}
I would like to get result. For example class_room_id = 1 and roomno only contain in roomno array. I may use command to get all as below.
$testtopics = TestTopic::where('class_room_id',1)->get();
But, I do not know to get record only class_room_id = 1 and roomno contain in array. Any advice or guidance on this would be greatly appreciated, Thanks
You can use like search in json fields
TestTopic::where('class_room_id',1)->where('roomno', 'like', '%"id": 1%')->first()
When checking for an array of values the whereIn method can be used:
$roomno = 'a:2:{i:0;s:1:"1";i:1;s:1:"2";}';
$testtopics = TestTopic::where('class_room_id',1)
->whereIn('roomno', unserialize($roomno))
->get();
Multiple where statements can be combined by passing an array:
$roomno = 'a:2:{i:0;s:1:"1";i:1;s:1:"2";}';
$users = TestTopic::where([
['class_room_id', '=', '1'],
['roomno', '=', $roomno],
])->get();

Combine 2 collections (keep the similar ones)

I've several collections, I want to keep only the elements that are present in each collection.
I went through the available methods, but I didn't find anything that would match.
$candidatesByConsultant = Consultant::find(request('consultant_id'))->candidates;
$candidatesByCreation = Candidate::whereBetween('created_at',[Carbon::parse(request('meeting_since')), Carbon::parse(request('meeting_to'))])->get();
Do you have any idea? :)
In order to have values that only present in both collection you must use intersect method:
$result = $candidatesByConsultant->intersect($candidatesByCreation);
The intersect method intersects the values of both collections. You can read it in Laravel's official documentation.
And in order to get have results that are not present in both collection you must use diff method:
$result = $candidatesByConsultant->diff($candidatesByCreation);
The diff method finds differences between collections. You can read it in Laravel's official documentation.
The intersect method may be suitable : https://laravel.com/docs/5.8/collections#method-intersect
Example taken from the documentation:
$collection = collect(['Desk', 'Sofa', 'Chair']);
$intersect = $collection->intersect(['Desk', 'Chair', 'Bookcase']);
$intersect->all();
// [0 => 'Desk', 2 => 'Chair']
However, especially if you are trying to intersect multiple collections of Eloquent models, it may not work since the equality between two models is defined by the Model::is() method. Check
https://laravel.com/docs/5.8/eloquent#comparing-models for more information about comparing two Eloquent models.
To handle this, I would do the following, assuming the primary key of your models is id:
$candidatesByConsultant = Consultant::find(request('consultant_id'))->candidates;
$candidatesByCreation = Candidate::whereBetween('created_at',[Carbon::parse(request('meeting_since')), Carbon::parse(request('meeting_to'))])->get();
$candidates = $candidatesByConsultant->merge($candidatesByCreation)->unique("id");
You may check the merge() and unique() documentations.
The built-in for this is $collection->intersect($other), but you can also achieve the desired result with a simple custom filter:
$left = collect([Model::find(1), Model::find(2), Model::find(3)]);
$right = collect([Model::find(1), Model::find(3), Model::find(5)]);
$result = $left->filter(function ($value, $key) use ($right) {
return $right->contains(function ($v, $k) use ($value) {
return $v->id === $value->id;
});
});
This will perform model comparison by id. It is not very performant though. Another approach would be to retrieve two arrays of ids, intersect them and filter the merged sets based on this list:
$left = collect([Model::find(1), Model::find(2), Model::find(3)]);
$right = collect([Model::find(1), Model::find(3), Model::find(5)]);
$merged = $left->merge($right);
$ids = array_intersect($left->pluck('id')->toArray(), $right->pluck('id')->toArray());
$result = $merged->filter(function ($value, $key) use ($ids) {
return in_array($value->id, $ids);
});

Using whereIn method to return multiple results for the same array value but at different index

$pidArray contains product ID's, some of those product ID's can be the same. I.E: 34 34 56 77 99 34. As is, it appears the whereIn method does not return results for a productId it has already found in $pidArray, even if it has a different index.
$productDataForOrder = Product::whereIn('id', $pidArray)->get(['id','price']);
$totalAmount = $productDataForOrder->sum('price');
$productDataForOrder now contains product data, but only for unique ProductID's in $pidarray. So when sum function is run, the sum is wrong as it does not take into account the price for multiple instances of the same productID.
The following code also does not return objects for every product ID in the array which are the same. So if $pidArray contains three identical product ID's, the query will only return a collection with one object, instead of three.
$query = Product::select();
foreach ($pidArray as $id)
{
$query->orWhere('id', '=', $id);
}
$productDataForOrder = $query->get(['id','price']);
$totalAmount = $productDataForOrder->sum('price');
You're not going to be able to get duplicate data the way that you're trying. SQL is returning the rows that match your where clause. It is not going to return duplicate rows just because your where clause has duplicate ids.
It may help to think of it this way:
select * from products where id in (1, 1)
is the same as
select * from products where (id = 1) or (id = 1)
There is only one record in the table that satisfies the condition, so that is all you're going to get.
You're going to have to do some extra processing in PHP to get your price. You can do something like:
// First, get the prices. Then, loop over the ids and total up the
// prices for each id.
// lists returns a Collection of key => value pairs.
// First parameter (price) is the value.
// Second parameter (id) is the key.
$prices = Product::whereIn('id', $pidArray)->lists('price', 'id');
// I used array_walk, but you could use a plain foreach instead.
// Or, if $pidArray is actually a Collection, you could use
// $pidArray->each(function ...)
$total = 0;
array_walk($pidArray, function($value) use (&$total, $prices) {
$total += $prices->get($value, 0);
});
echo $total;
The whereIn method only limits the results to the values in the given array. From the docs:
The whereIn method verifies that a given column's value is contained within the given array
Id make a query variable and loop through the array adding to the query variable in each pass. Something like this:
$query = Product::select();
foreach ($pidArray as $id)
{
$query->where('id', '=', $id);
}
$query->get(['id','price']);
Here is a code that would work for your use case expanding on #patricus
You first fetch an array of key as id and value as price from the products table
$prices = Product::whereIn('id', $pidArray)->lists('price', 'id');
$totalPrice = collect([$pidArray])->reduce(function($result, $id) use ($prices) {
return $result += $prices[$id];
}, 0);

Resources