Laravel Eloquent get every nth of relation - php

I am querying a relation from a model, but since I want to limit the amount of rows that the relation returns to a set number (in this example 18), I've mapped the relation.
$sensors = Sensor::where('building_id', $request->building_id)->with('data_sensor')->get()->map(function($sensor) {
$sensor->setRelation('data_sensor', $sensor->data_sensor->sortByDesc('created_at')->take(18)->values());
return $sensor;
});
This works fine. However I am trying to get every nth row of my relation, in this example I want every 6th row.
I've tried the following (added whereRaw), but this gave an error that the whereRaw method doesn't exist.
$sensors = Sensor::where('building_id', $request->building_id)->with('data_sensor')->get()->map(function($sensor) {
$sensor->setRelation('data_sensor', $sensor->data_sensor->sortByDesc('created_at')->whereRaw( DB::raw('(`id`) % 6 != 0') )->take(18)->values());
return $sensor;
});
How can I get every nth of my relation, with a limit so it doesn't return all rows of the relation?

You are trying to use a querybuilder method in a collection, that's the reason for the error.
Try this:
$sensors = Sensor::where('building_id', $request->building_id)
->with('data_sensor')
->get()
->map(function($sensor) {
$sensor->setRelation(
'data_sensor',
$sensor->data_sensor->sortByDesc('created_at')->filter(function($s) { return $s->id % 6 != 0; })->take(18)->values());
return $sensor;
});

Related

Why does my relationship return results but not "withCount"?

I have a model which has a relationship with "where" and "if". I need to retrieve all the models where the count of the relationship is > 1.
When I try to get it with "withCount", I end up having models which have relationships having 0 to the "shared_job_offers_count" when they should have 1. However, it works properly for some model.
I noticed that it happens when the "$this->isSubscribedPremium()" in the "if" is true.
RELATIONSHIP
public function shared_job_offers() {
if($this->isSubscribedPremium()) {
return $this->hasMany('App\JobOffer')->where('disable_share', false);
} else {
return $this->hasMany('App\JobOffer')->where('manual_share', true);
}
}
RETRIEVING THE RESULTS
App\Employer::withCount('shared_job_offers')->get()->where('shared_job_offers_count', '>', 0)
RECAP:
withCount returns 0 for some models, 1 for the others
it returns 0 mainly when "$this->isSubscribedPremium()" is true
i can get all the proper relationships if I just retrieve it directly.
Any idea?

Laravel Count Vehicles W/O Images

I am trying to get some help to rewrite some stuff that got thrown at me on a project I am working on to increase speed. I am working in Laravel 5.4. I can trying to count how many vehicles do not have images without looping through each vehicle.
Each vehicle has a vehicle_id that corrects to the vehicle_id col in the vimages table.
I am trying to eliminate having to loop through every single vehicle and make separate SQL calls for each vehicle.
My Function To Count:
'missingDescription' => $inv->where('vehicle_type','=','NEW')->where('description','=', '')->where('description','=', null)->count(),
Original Function To Count:
'images' => $inventories->filter(function($row) {
if ($row->Images()->get()->count() <= 0) {
return true;
}
return false;
})->count(),
'stockphotos' => $inventories->filter(function($row) {
return $row->Images()->get()->filter(function($item) {
return $item->isStockPhoto && !$item->isDeleted;
})->count() > 0 ? true : false;
})->count(),
Images function:
public function images() {
return $this->hasMany('App\Vimage');
}
You could use withCount. so when you get the model originally add withCount('images') which will append images_count to the returned model.
$inventories = Inventory::withCount('images')->get();
'images' => $inventories->where(images_count, 0)->count()
Here's the laravel page for reference Querying Relationship Absence
You need to use a search closure for the description, since you're looking for where it's either an empty string OR null.
'missingDescription' => $inv->where('vehicle_type','=','NEW')
->where(function($query) {
$query->where('description','=', '')
->orWhereNull('description');
})->count(),

Laravel: Count number of rows in a relationship

I have the following relationship:
A venue has many offers
A offer has many orders
I have the following Eloquent model to represent this:
class Venue {
public function orders()
{
return $this->hasManyThrough(Order::class, Offer::class);
}
}
I want to determine the total number of orders for venues with location_id = 5 using Laravel's Eloquent model.
The only way I managed to do this is as follows:
$venues = Venue::where('location_id', 5)->with('orders')->get();
$numberOfOrders = 0;
foreach($venues as $venue) {
$numberOfOrders += $venue->orders->count();
}
dump($numberOfOrders); // Output a single number (e.g. 512)
However, this is obviously not very efficient as I am calculating the count using PHP instead of SQL.
How can I do this using Eloquent model alone.
You can use Eloquent. As of Laravel 5.3 there is withCount().
In your case you will have
$venues = Venue::where('location_id', 5)->with('orders')->withCount('orders')->get();
Then access it this way
foreach ($venues as $venue) {
echo $venue->orders_count;
}
Can find reference here: https://laravel.com/docs/5.3/eloquent-relationships#querying-relations
$venues = Venue::with([
'orders' => function ($q) {
$q->withCount('orders');
}
])->get();
then use it this way for getting single record
$venues->first()->orders->orders_count();
Alternatively, you can use this way too for collections
foreach($venues as $venue)
{
echo $venue->order_count;
}
If you are using Laravel 5.3 or above you can use withCount.
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. For example:
$venues = Venue::withCount(['orders'])->get;
foreach ($venues as $venue) {
echo $venue->orders_count;
}
You can read more about withCount in the Laravel Documentation.
If you are using lower than 5.3, you can make a custom relation on your Venue model:
public function ordersCount()
{
return $this->belongsToMany('App\Models\Order')
->selectRaw('venue_id, count(*) as aggregate_orders')
->groupBy('venue_id');
}
public function getOrderCount()
{
// if relation is not loaded already, let's do it first
if (!array_key_exists('ordersCount', $this->relations)) {
$this->load('ordersCount');
}
$related = $this->getRelation('ordersCount')->first();
// then return the count directly
return ($related) ? (int) $related->aggregate_orders : 0;
}
which can then be used as: Venue::with('ordersCount');. The benefit of this custom relation is you only are querying the count rather than the querying all of those relations when they are not necessary.

Laravel relations, select next raleted row from database.

I have related items in my database. I selected all of items from database by related id:
$next_stock = $this->model->get()->where('part_id', $in_data['part_id'])->all();
and I collection of rows grouped by one specific id, like on the picture. All of them selected by "part_id":
Selection Of Items
Grouped By Same Id
Also with this line of code i can select one of the items from this collection:
$next_stock = $this->model->get()->where('id', $old_stock['id'])->where('part_id', $in_data['part_id'])->first();
But how can I select the following items after this one?
Or, how can I select second or third item from this collect?
I cannot just increase id number by one from first, because sometimes this item ids not following each other.
Having a collection, you can take a specific element in the position with a combination of take() and last().
$collection = $this->model->get()->where('part_id', $in_data['part_id'])->all();
$second = $collection->take(2)->last(); //if this doesnt work, do it in 2 steps
$third = $collection->take(3)->last(); //if this doesnt work, do it in 2 steps
If you don't have a collection, take directly from database like this
$second = $this->model
->where('part_id', $in_data['part_id'])
->skip(1)
->first();
If it doesn't work with first()
$collect = $this->model
->where('part_id', $in_data['part_id'])
->skip(1)
->take(1)
->get();
$second = $collect->first();
Edit
skip() and take() are actually part of the query builder, not eloquent model. So it won't work with Eloquent in Laravel 5.4
Try with
$collect = $this->model
->where('part_id', $in_data['part_id'])
->get(1); //For the second record, 0 being the first
If you aren't doing it yet, you should set your model's relationships.
E.g. If you use "one-to-many", Eloquent will automatically determine the proper foreign key column on the model for you.
$parts = App\Stock::find(1)->partId;
foreach ($parts as $part) {
//
}

Counting total distant relationships in Laravel (eager loading?)

I'm having issues getting a proper count total with my Laravel model.
Model Structure
User
Item
ItemLike
A user can have multiple Items, and each of these Items can have multiple ItemLikes (when a user 'likes' the item).
I can easily get the individual ItemLike counts when using an Item model:
return $this->itemLikes()->count();
But I can't figure out how to get the total # of ItemLike's a User has across all the Item's he owns.
EXAMPLE
User A has 3 Items. Each Item has 5 ItemLike's, for a grand total of 15.
I tried using eager loading on the User model like this:
return $this->items()->with('itemlikes')->get()->count();
But that returns 3 (the # of Items)
These are the queries it ran, which appears like the second query is the one I want, yet every way I try it I still get 3 instead of 15
select * from `items` where `items`.`user_id` = '1000'
select * from `item_likes` where `item_likes`.`item_id` in ('1000', '1001', '1002')
After suggestions from others I found 2 solutions to get the result.
Using whereIn:
$itemViewCount = ItemView::
whereIn('item_views.item_id', $this->items()->lists('id'))
->count();
return $itemViewCount;
2 queries for a total of 410μs
Using join:
$itemViewCount = $this->items()
->join('item_views', 'item_views.item_id', '=', 'items.id')
->count();
return $itemViewCount;
2 queries for a total of 600μs
Isn't it just a case of creating a method that would return the number of items for the model. e.g.:
#UserModel
public function nbLikes()
{
$nbLikes = 0;
foreach($this->items() as $item) {
$nbLikes += $item->itemLikes()->count();
}
return $nbLikes;
}
And then User::nbLikes() should return the piece of data you are looking for?
try this:
$query="select count(il.id) from item_likes il,item itm where il.item_id=itm.id and tm.user_id=1000";

Categories