问题
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 id
s in a single model, each model will have it's own related models but you may get the related model's id
s 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