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
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?
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(),
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.
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) {
//
}
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";