I'm trying to build a small application on laravel-5.4 where I'm having a relational query something like this:
$companies = Company::where('is_client', '=', 1)
// load count on distant model
->with(['interactionSummaries.interaction' => function ($q) {
$q->withCount(['contactsAssociation' => function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Investor');
});
}]);
}])
->get();
Now I want to collect all the contact_association_counts generated from the query and add it to individual company collection For this I'm using pluck, collapse and sum method, but I don't know it is not calculating as desired. Following is the screenshots:
I get list of collection as following:
Now I get the attributes:
Now relational data:
Now interaction data, where the count belongs:
So for this I tried:
$companies = Company::where('is_client', '=', 1)
// load count on distant model
->with(['interactionSummaries.interaction' => function ($q) {
$q->withCount(['contactsAssociation' => function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Investor');
});
}]);
}])
->get()
->transform(function ($company) {
$company->contacts_association_count = $company->interactionSummaries
->pluck('interaction.contacts_association_count')
->collapse()
->sum();
return $company;
});
But this is not calculating the counts, all the counts are coming to 0
Help me out in this. Thanks
I believe that your problem is the ->collapse() seeing your example after the ->pluck('interaction.contacts_association_count') you should have a flat array as [1,2,3,4,5] if you apply collapse() to a flat array it returns a void array [] and the sum of a void array is 0
$companies = Company::where('is_client', '=', 1)
// load count on distant model
->with(['interactionSummaries.interaction' => function ($q) {
$q->withCount(['contactsAssociation' => function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Investor');
});
}]);
}])
->get()
->transform(function ($company) {
$company->contacts_association_count = $company->interactionSummaries
->pluck('interaction.contacts_association_count')
//->collapse()
->sum();
return $company;
});
I hope it works... good luck!
Related
I wanna ask about some nested relation using whereHas query in laravel, well for the first I will explain the model first before I going through into my main case.
this is my model :
StockIn.php
class StockIn extends Model {
protected $primaryKey = "id_stock_in";
/* this only column that I wanna show, and skip the else column */
protected $fillable = ['stock_in_id_type'];
public function type_of_items() {
return $this->belongsTo('App\TypeOfitem', 'stock_in_id_type');
}
}
TypeOfItem.php
class TypeOfItem extends Model {
protected $primaryKey = "id_type_item";
/* this only column that I wanna show, and skip the else column */
protected $fillable = ['type_id_item'];
public function items() {
return $this->belongsTo('App\Item', 'type_id_item');
}
public function stock_ins() {
return $this->hasMany('App\StockIn');
}
}
Item.php
class Item extends Model {
protected $primaryKey = "id_item";
/* this only column that I wanna show, and skip the else column */
protected $fillable = ['item_id_common_unit'];
public function common_units() {
return $this->belongsTo('App\CommonUnit', 'item_id_common_unit');
}
public function type_of_items() {
return $this->hasMany('App\TypeOfItem');
}
}
CommonUnit.php
class CommonUnit extends Model {
protected $primaryKey = "id_common_unit";
/* this only column that I wanna show, and skip the else column */
protected $fillable = [/* describe column */];
public function items() {
return $this->hasMany('App\Item');
}
}
I already describe all of my model, as you can see all table (child) have some relation to each parent like :
stockIn -> typeOfItem (relation between child and parent)
typeOfItem -> Item (relation between child and parent)
Item -> CommonUnit (relation between child and parent)
so for the question is how to make some query to getting data in nesting relationship when I do search for all data in child or parent? I already made the query but the result is not same with my expectation or null, it can be said that.
StockInController
$getData = StockIn::with(['type_of_items' => function ($query) {
$query->select('id_type_item', 'type_id_item', 'code_type_of_item', 'type_of_item')
->with(['items' => function ($query) {
$query->select('id_item', 'item_id_common_unit', 'name_item')
->with(['common_units' => function ($query) {
$query->select('id_common_unit', 'name_unit');
}]);
}]);
}])
->with(['stock_out_left_join' => function ($query) {
$query->select('id_stock_out', 'stock_out_id_stock_in');
}])
->whereHas('type_of_items', function ($query) use ($search) {
$query->where('code_type_of_item', 'like', "%{$search}%");
})
->whereHas('type_of_items.items', function ($query) use ($search) {
$query->orWhere('name_item', 'like', "%{$search}%");
})
->whereHas('type_of_items.items.common_units', function ($query) use ($search) {
$query->orWhere('name_unit', 'like', "%{$search}%");
})
->orWhere('created_by', 'like', "%{$search}%")
->orWhere('edited_by', 'like', "%{$search}%")
->get()
->toArray();
Oh ya I will send example data for my query in this bellow :
but when I do search with some keyword is not worked, for example when I do type "adaptor", the result is empty or nothing show on my data, so what I must to do? Thank you
Okay for a while I was think about my problem finally I got the answer. Okay for sharing to everyone I will explain a little bit for the answer.
So the query what I wrote on the controller, I change into this :
$getData = StockIn::with(['type_of_items' => function ($type_of_item) {
$type_of_item->select('id_type_item', 'type_id_item', 'code_type_of_item', 'type_of_item')
->with(['items' => function ($item) {
$item->select('id_item', 'item_id_common_unit', 'name_item')
->with(['common_units' => function ($common_unit) {
$common_unit->select('id_common_unit', 'name_unit');
}]);
}]);
}])
->with(['stock_out_left_join' => function ($stock_out_left_join) {
$stock_out_left_join->select('id_stock_out', 'stock_out_id_stock_in');
}])
->whereHas('type_of_items', function ($type_of_items_search) use ($search) {
$type_of_items_search->where('code_type_of_item', 'like', "%{$search}%")
->orWhere('type_of_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items', function ($items_search) use ($search) {
$items_search->where('name_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items.common_units', function ($common_units_search) use ($search) {
$common_units_search->where('name_unit', 'like', "%{$search}%");
})
->orWhere('created_by', 'like', "%{$search}%")
->orWhere('edited_by', 'like', "%{$search}%")
->get()
->toArray();
As you can see my new query has a new parameter in every with function and I was naming all the parameter with different name, and not like first name before query, so the problem is the ambiguous paramater in every single with function because this query based on nested relation so I must make the parameter name different each other. Or you want make them into split one by one and not using the nested with function you can use this query too, I put on this bellow :
$getData = StockIn::with(['type_of_items' => function ($query) {
$query->select('id_type_item', 'type_id_item', 'code_type_of_item', 'type_of_item');
}])
->with(['type_of_items.items' => function ($query) {
$query->select('id_item', 'item_id_common_unit', 'name_item');
}])
->with(['type_of_items.items.common_units' => function ($query) {
$query->select('id_common_unit', 'name_unit');
}])
->with(['stock_out_left_join' => function ($query) {
$query->select('id_stock_out', 'stock_out_id_stock_in');
}])
->whereHas('type_of_items', function ($query) use ($search) {
$query->where('code_type_of_item', 'like', "%{$search}%")
->orWhere('type_of_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items', function ($query) use ($search) {
$query->where('name_item', 'like', "%{$search}%");
})
->orWhereHas('type_of_items.items.common_units', function ($query) use ($search) {
$query->where('name_unit', 'like', "%{$search}%");
})
->orWhere('created_by', 'like', "%{$search}%")
->orWhere('edited_by', 'like', "%{$search}%")
->get()
->toArray();
I already tried that query and it's work too (with the same name parameter in every single with function).
Have a query, how I can filter results by translation relation (by name column)
$item = Cart::select('product_id','quantity')
->with(['product.translation:product_id,name','product.manufacturer:id,name'])
->where($cartWhere)
->get();
my model
Cart.php
public function product($language = null)
{
return $this->hasOne('App\Models\Product','id','product_id');
}
Product.php
public function translations()
{
return $this->hasMany('App\Models\ProductTranslation','product_id','id');
}
Update v1.0
do like this, but query takes too long time
$item = Cart::select('product_id','quantity')
->with(['product.translation', 'product.manufacturer:id,name'])
->where($cartWhere)
->when($search,function ($q) use ($search) {
$q->whereHas('product.translation', function (Builder $query) use ($search) {
$query->where('name', 'like', '%'.$search.'%');
$query->select('name');
});
}
)
->get() ;
Inside the array within your with() method, you can pass a function as a value.
Cart::select('product_id','quantity')
->with([
'product', function($query) {
$query->where($filteringAndConditionsHere);
}
]);
https://laravel.com/docs/7.x/eloquent-relationships#eager-loading
I am doing a filter using relations here is my controller code:
$userList = User::with(['role' ,'userMetaData','userBet','userComission','userPartnership'])
->where('deleted', '=', '0')
->when($request->parent_id, function ($builder, $parent_id) {
return $builder->where('parent_id', $parent_id);
})
->when($request->role_id, function ($builder, $role_id) {
return $builder->where('role', $role_id);
})
->when($request->to && $request->from , function ($builder) use ($request) {
return $builder->whereBetween('exposure_limit', [$request->from, $request->to]);
})
->when($request->city, function ($builder) use ($request) {
return $builder->whereHas('userMetaData', function($query) use ($request){
$query->where('city', $request->sport);
});
})
->orderBy('created_at', 'DESC')
->get();
In this case(in my code) i am trying to use whereHas() to filter a data from another table(within relations) by eloquent but it's something i am missing:
here in your case, when you use Wherehas to userMetaData it'll filter and gives you only those users who's has city as $request->sport..
In another case, you've used with('userMetaData') which means whatever users you got in filter return all userMetaData.
->when($request->city, function ($builder) use ($request) {
return $builder->whereHas('userMetaData', function($query) use ($request){
$query->where('city', $request->sport);
})->with(['userMetaData' => function($q) use ($request) {
$q->where('city', $request->sport);
}]);
})
Remove userMetaData from User::with(['role','userBet','userComission','userPartnership'])
I'm building a small application on Laravel 5.4 where I'm having data sets to are being fetched from the relationship something like this:
$meetings = Company::where('name', 'Atlanta Ltd')
->withCount(['interactions as investors'=> function ($q) {
$q
->whereBetween('schedule', [Carbon::now()->subMonths(6), Carbon::now()->subMonths(1)])
->whereHas('contactsAssociation', function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Investor');
});
});
}])->get()
->transform(function ($company) {
$company->investors_count = $company->interactions
->pluck('investors_count')
->sum();
return $company;
});
Currently I'm getting the number of interaction as investor_counts between that particular date, I want to fetch the counts between certain date fields, i.e. suppose I want to have the data to be fetched for consecutive 6 months, I mean data of 6 different months something like this:
->whereBetween('schedule', [Carbon::now()->subMonths(6), Carbon::now()->subMonths(5)])
and
->whereBetween('schedule', [Carbon::now()->subMonths(5), Carbon::now()->subMonths(4)])
and
->whereBetween('schedule', [Carbon::now()->subMonths(4), Carbon::now()->subMonths(3)])
And the list goes on similar to above differences. And I don't want to implement multiple foreach loops, is there any way out with Laravel Collection where I can manipulate such data the get the output. Please guide me. Thanks.
Edit:
Let me explain in better way, currently I'm using this code to get my desired data:
public function investorGraphData(Request $request)
{
$weekInvestorData = $weekResearchData = [];
if($request->timeFormat == 'month')
{
for($i=0; $i<6; $i++)
{
$meetings = Company::where('name', $request->client)
->withCount(['interactions as investors'=> function ($q) use($i) {
$q
->whereBetween('schedule', [Carbon::now()->subMonth($i+1), Carbon::now()->subMonth($i)])
->whereHas('contactsAssociation', function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Investor');
});
});
}])
->withCount(['interactions as research' => function($q) use($i) {
$q
->whereBetween('schedule', [Carbon::now()->subMonth($i+1), Carbon::now()->subMonth($i)])
->whereHas('contactsAssociation', function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Research');
});
});
}])
->get();
$weekInvestorData[] = $meetings[0]->investors_count;
$weekResearchData[] = $meetings[0]->research_count;
}
return response()->json(['investor' => $weekInvestorData, 'research' => $weekResearchData], 200);
}
elseif ($request->timeFormat == 'week')
{
for($i=0; $i<6; $i++)
{
$meetings = Company::where('name', $request->client)
->withCount(['interactions as investors'=> function ($q) use($i) {
$q
->whereBetween('schedule', [Carbon::now()->subWeek($i+1), Carbon::now()->subWeek($i)])
->whereHas('contactsAssociation', function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Investor');
});
});
}])
->withCount(['interactions as research' => function($q) use($i) {
$q
->whereBetween('schedule', [Carbon::now()->subWeek($i+1), Carbon::now()->subWeek($i)])
->whereHas('contactsAssociation', function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Research');
});
});
}])
->get();
$weekInvestorData[] = $meetings[0]->investors_count;
$weekResearchData[] = $meetings[0]->research_count;
}
return response()->json(['investor' => $weekInvestorData, 'research' => $weekResearchData], 200);
}
else
return response()->json(['message' => 'No input given'], 200);
}
Is there any way to shorten this code through collection?
you may try to give column as different name,
For example :
$meetings = Company::where('name', 'Atlanta Ltd')
->withCount(['interactions as investors'=> function ($q) {
$q
->whereBetween('schedule as schedule6to5', [Carbon::now()->subMonths(6), Carbon::now()->subMonths(5)])
->whereBetween('schedule as schedule5to4', [Carbon::now()->subMonths(5), Carbon::now()->subMonths(4)])
->whereBetween('schedule as schedule4to3', [Carbon::now()->subMonths(4), Carbon::now()->subMonths(3)])
->whereHas('contactsAssociation', function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Investor');
});
});
}])->get()
->transform(function ($company) {
$company->investors_count = $company->interactions
->pluck('investors_count')
->sum();
return $company;
});
May be this will work.
I'm trying to query a nested relation and getting the count of distant model count, I'm transforming this to a variable but it is not happening:
$companies = Company::where('is_client', '=', 1)
// load count on distant model
->with(['interactionSummaries.interaction' => function ($q) {
$q->withCount(['contactsAssociation' => function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Research');
});
}]);
}])
->get()
->transform(function ($company) {
$company->contacts_association_count = $company->interactionSummaries
->pluck('interaction.contacts_association_count')
->collapse()
->sum();
});
When I try to dd($companies) or even return $companies I get null values placed in each array index
But when I do dd($company) inside transform
->transform(function ($company) {
$company->contacts_association_count = $company->interactionSummaries
->pluck('interaction.contacts_association_count')
->collapse()
->sum();
dd($company);
});
I get the single collection which states my query is running properly:
If I remove transform part and simply get the collection:
$companies = Company::where('is_client', '=', 1)
// load count on distant model
->with(['interactionSummaries.interaction' => function ($q) {
$q->withCount(['contactsAssociation' => function ($q) {
$q->whereHas('company', function ($q) {
$q->where('type', 'like', 'Research');
});
}]);
}])
->get()
I'm getting the desired output, But I don't know what it is happening after transform execution. In fact it is not plucking and adding the sum, as I'm getting all 0 in the counts.
I've marked them with red. Help me out in this
I think you are missing a return statement in the transform closure.
You need to put return $company statement in transform.