问题
I would like to make eager load of a related model. however, instead of getting the whole related model, i'd like to retrieve just its id. so at the end, i'll have something like the following:
{
"error": false,
"invoices": {
"id": 5,
"biz_id": 7,
"doc_num": 0,
"type": 1,
"due_date": "0000-00-00",
"status": null,
"to": null,
"**related_model**": [1,2,3,4]
}
I'd prefer avoiding loops.
UPDATE
as I understand I couldn't make it without loops, i have done the following:
$data = array();
//get models
$models = IncomeDoc::with('relatedReceipts')
->where('type', '!=', 2)
->get()
->toArray();
foreach ($models as $model)
{
$model['related_receipts'] = array_pluck($model['related_receipts'], 'id');
$data[] = $model;
}
Now here is my question: is there any way that i could do that data manipulation in the model itself? this code is not clean and can not be re-used, and i'd rather avoid it.
回答1:
You can use the relationship to get the identifiers.
Custom function:
public function myRelationIds() { return $this->myRelation->lists('id'); }You call the function and add the results to the response.
Through accessor
public function getMyRelationIdsAttribute() { return $this->myRelation->lists('id'); }Now, you can make this attribute is automatically added when the model becomes Array or JSON with appends property:
protected $appends = array('my_relation_ids');
Note that it's important to continue eager loading relation to prevent excessive queries. And given that the relationship will continue loading, you might want to hide it and only have identifiers:
protected $hidden = array('myrelation');
回答2:
The very straight solution would be to define visible fields in your related model:
class RelatedModel extends Eloquent
{
protected $visible = array('id');
}
Note, this would be the only field returned by toArray() method everywhere.
回答3:
Directly you won't be able to get all the ids in a single model, each model will have it's own related models but you may get the related model's ids using something like following, for example Post is main/parent model and Post has many comments, so it could be done using this:
$ids = array();
$posts = Post::with(array('comments' => function($q){
// post_id is required because it's the foreign key for Post
$q->select(array('id', 'post_id'));
}))->get()->map(function($item) use(&$ids){
$ids[] = $item->comments->fetch('id')->toArray();
});
// Get all ids in one array
$ids = array_flatten($ids);
Now, you just rename the Post with Invoice and comments with related model name. Here Post has many comments with following relation defined in the Post model:
// Post model
public function comments()
{
return $this->hasMany('Comment'); // Comment model
}
回答4:
I was having some problems with eager loading recently myself. My suggestion is to just replicate what eager loading does, which is run a second query including a whereIn() of the ids from the first model. Going back to your example
$modelsQuery = IncomeDoc::where('type', '!=', 2);
$models = $modelsQuery->get();
$modelIds = $models->select('id')->lists('id');
$relatedReceiptsQuery = RelatedReceipts::whereIn(`model_id`,$modelIds);
$relatedReceipts = $relatedReceiptsQuery->get();
$relatedReceiptsLookup = $relatedReceiptsQuery->lists(`id`,`model_id`)
You'll be able to iterate through $models, and retrieve $relatedReceipts->find($relatedReceiptsLookup[$models->id]). You could simplify this further if you only want a single field from RelatedReceipts, or you could probably add toArray() to $relatedReceipts and search the array instead of using $relatedReceiptsLookup to search the models.
来源:https://stackoverflow.com/questions/22802670/laravel-4-eager-load-as-a-list-of-ids