Laravel - Count of items through with belongs to - laravel

A company can have many delivery dates. A delivery date may have many entries. The Entry model contains
public function company()
{
return $this->belongsTo(Company::class);
}
public function delivery_date()
{
return $this->belongsTo(MgDeliveryDate::class, 'mg_delivery_date_id');
}
What I want is a count of how many entries each delivery date has for each company. For example, something like
$companies = Company->with('delivery_dates', 'delivery_dates.entries')->withCount('delivery_dates.entries')
So if my data was
Company Delivery Date Entry Number
A 1/2/2020 1
A 1/2/2020 2
A 2/2/2020 3
B 1/2/2020 4
I would get two companies, company A with two delivery dates and a count of 2 for the first date(1/2/2020) and 1 for the second date(2/2/2020) and company B with one delivery date, with an entry count of 1.

Good question. Give this a shot.
$companies = Company::with('delivery_dates.entries')->get();
$companies->map(function($company){
return $company->delivery_dates->map(function($delivery){
return $delivery->entries->count();
})->groupBy('delivery_date');
});
I have used Laravel Collection map() method.

// i am not sure what you actually want.. if you want the data like this then you can try this
[
{ company:abc , date:[{1/20} , {2/20} ...] , entry:[{1} ,{2} ...]} ,
{},
....
]
Company model
public function entry()
{
return $this->hasMany(entry::class);
}
And Then
$companies = Company::withCount(['entry', 'delivery_dates' => function ($query) {
$query->where(your condition);
}])->get();

You may write:
$companies = Compnay::with(['delivery_dates' => function ($q) {
$q->withCount('entries');
}])
->get();
You will get the following result:

Related

Get Data through relation in laravel

I'm using this query to get data using relation
return Product::with('attributes')
->whereHas('attributes', function ($query) use ($attribute_id,$attribute_value){
$query->whereIn('attribute_id', $attribute_id);
$query->whereIn('value', $attribute_value);
})
->paginate(10);
$attribute_id and $attribute_value are arrays, i'm getting data using this relation but when $attribute_id and $attribute_value are empty then i'm not getting any result but it should return result through product table if there are no attributes.
I have changed it to something like this:
if(!empty($attribute_id))
{
$query->whereIn('attribute_id', $attribute_id);
}
if(!empty($attribute_value))
{
$query->whereIn('value', $attribute_value);
}
model relation :
public function attributes()
{
return $this->hasMany(ProductsAttribute::class, 'product_id ');
}
Table:
id | Title | Price
1 Title 1 5000
2 Product 2 7000
this is related to product_attribute table
id | product_id | attribute_id | attribute_name | value
1 1 5 Color Red
2 1 6 Size XL
3 2 5 Color Green
Is there any other way to make a check in query so that if attributes are not provided then atleast product data should return.
A cleaner way might be to use local scopes. That way, your controllers will look cleaner. It also makes the code easily testable. Here is how I might approach this.
NOTE: Code hasn't been tesed.
In your controller:
return Product::with([
'attributes' => function ($query) use ($attribute_id, $attribute_value) {
return $query->inAttributeId($attribute_id)
->inAttributeValue($attribute_value);
}
])->paginate(10);
In your ProductsAttribute model:
public function scopeInAttributeId($query, $attributeId)
{
if (empty($attributeId)) {
return $query;
}
return $query->whereIn('attribute_id', $attributeId);
}
public function scopeInAttributeValue($query, $attributeValue)
{
if (empty($attributeValue)) {
return $query;
}
return $query->whereIn('value', $attributeValue);
}
As you can see, the scopes modify the query only if there are values in the passed in array. If the passed in array is empty, it returns the original query.

Get only one column from relation

I have found this: Get Specific Columns Using “With()” Function in Laravel Eloquent
but nothing from there did not help.
I have users table, columns: id , name , supplier_id. Table suppliers with columns: id, name.
When I call relation from Model or use eager constraints, relation is empty. When I comment(remove) constraint select(['id']) - results are present, but with all users fields.
$query = Supplier::with(['test_staff_id_only' => function ($query) {
//$query->where('id',8); // works only for testing https://laravel.com/docs/6.x/eloquent-relationships#constraining-eager-loads
// option 1
$query->select(['id']); // not working , no results in // "test_staff_id_only": []
// option 2
//$query->raw('select id from users'); // results with all fields from users table
}])->first();
return $query;
In Supplier model:
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id')
//option 3 - if enabled, no results in this relation
->select(['id']);// also tried: ->selectRaw('users.id as uid from users') and ->select('users.id')
}
How can I select only id from users?
in you relation remove select(['id'])
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id');
}
now in your code:
$query = Supplier::with(['test_staff_id_only:id,supplier_id'])->first();
There's a pretty simple answer actually. Define your relationship as:
public function users(){
return $this->hasMany(User::class, 'supplier_id', 'id');
}
Now, if you call Supplier::with('users')->get(), you'll get a list of all suppliers with their users, which is close, but a bit bloated. To limit the columns returned in the relationship, use the : modifier:
$suppliersWithUserIds = Supplier::with('users:id')->get();
Now, you will have a list of Supplier models, and each $supplier->users value will only contain the ID.

How to order by column in nested level relationship in Laravel and get first order by?

I have two model.finance has many price.i want to get just one price (last record according to time) for every finance.so used function and order by and first of each orderby.but this just works for first finance and the other i get null in the with relation.
public function prices()
{
return $this->hasMany(Price::class, 'finance_id');
}
public function finances()
{
return $this->belongsTo(Finance::class, 'finance_id');
}
$finances = Finance::with(['prices' => function ($query) {
$query->orderBy('created_at', 'desc')->first();
}])->get();
Create new relationship in your Finance model to get latest price:
public function latestPrice()
{
return $this->hasOne(Price::class)->latest();
}
Change your query as below:
$finances = Finance::with('latestPrice')->get();

Laravel: How to get data from 3 tables with relationship

I have 3 Tables:
Customers
id
name
Sales
customer_id
sale_date
Contacts
customer_id
contact_date
There aren't any update operations in the contacts table. Each process opens a new record in the contacts table. So, a user can have more than one records in the contacts table.
Here are my relations in models:
Customer
public function contacts()
{
return $this->hasMany(Contact::class);
}
public function sales()
{
return $this->hasMany(Sale::class);
}
Contact
public function customer()
{
return $this->belongsTo('App\Customer', 'customer_id');
}
Sale
public function customer()
{
return $this->belongsTo('App\Customer');
}
I would like to have the latest record of the contacts table and make it join with the other related tables.
Here is the query which I have tried:
$record = Contact::groupBy('customer_id')
->select(DB::raw('max(id)'));
$result = Customer::query();
$result->where('is_active', 'YES');
$result->with('sales');
$result->whereHas('contacts', function ($q) use($record){
return $q->whereIn('id', $record)->where('result', 'UNCALLED');
});
return $result->get();
In the blade file, I get some result in foreach loops. However, I am unable to get the related data from the sales and contacts table.
#foreach($result as $item)
#foreach($item->sales as $sale) // Has no output and gives error: Invalid argument supplied for foreach()
#foreach($item->contacts as $contact) // Has no output and gives error: Invalid argument supplied for foreach()
Can anyone help me how to display the sale and contact date? Or any idea for how to improve this code quality?
If you want the latest record of the contacts you can declare another relationship on the Customer model, e.g.:
public function latest_contact()
{
return $this->hasOne(Contact::class)->latest('contact_date');
}
BTW you can always declare one or more hasOne additional relationship if you have a hasMany in place the foreign key used is the same.
In this way you can retrieve latest_contact eager loaded with your Customer model:
$customer = Customer::with('latest_contact')->find($id);
Or use this relationship in your queries, something like that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->whereHas('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
Or that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->with('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
If you want you can declare last_contact with the additional where:
public function latest_contact()
{
return $this->hasOne(Contact::class)
->where('result', 'UNCALLED')
->latest('contact_date');
}
This way all other queries should be easier.
I hope this can help you.
I'm not sure, but can you try to do the following:
return Customer::where('is_active', 'YES')
->with([
'sale',
'contact' => function ($query) use($record) {
return $query->whereIn('id', $record)->where('result', 'UNCALLED');
}
])->get();

Ordering data from a table with the help of other table by using relationships with laravel?

I have the controller with the query:
$Comments = Comment::orderBy('id_parent', 'asc')->get();
And I have the Comment model:
class comment extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
public function votes()
{
return $this->hasMany('App\Vote', 'comment_id', 'id_comment');
}
}
I want to retrieve the comments data sorted in a specific way, every comment has multiply votes voted by different users, so the count('vote') is the number of votes for each comment. The problem is that I am stuck with how to call the specific votes function in the model so that it can count the column vote and order it either asc or desc.
That in the end I can have the $Comments sorted also by the total number of votes.
You can try as:
$Comments = Comment::withCount('votes')->orderBy('votes_count', 'asc')->get();
withCount() method is used when you want to count the number of results from a relationship without actually loading them, which will place a {relation}_count column on your resulting models.
Using sortBy:
$comments=Comment::with('votes')->get()->sortBydesc('votes');
foreach($comments as $comment)
{
echo $comment->votes->count('vote');
}

Resources