问题
A : User,
B : Conversations,
C : Messages
I want to get the conversation together with it's most recent message in an A->B->C relationship from A.
Working relationships in model
User belongsToMany Conversation
Conversation belongsToMany User
Conversation hasMany Message
Message belongsTo Conversation
User hasMany Message
Message belongsTo User
**note: User and Conversation are related to a many2many relationship connected
by a pivot table
I've tried
$user->load(['conversations' => function($q)
{
$q->orderBy('created_at', 'desc');
$q->with('Messages')->orderBy('created_at','desc');
}]);
It nearly worked but it doesn't get the last message. Instead, it loads all of the messages belonging to that conversation.
Unwanted result from above code
array (size=7)
'id' => int 90
'name' => string 'haha,hehe' (length=9)
'created_at' => string '2014-07-03 15:04:04' (length=19)
'updated_at' => string '2014-07-03 15:04:04' (length=19)
'microseconds' => string '1404370893302' (length=13)
'pivot' =>
array (size=2)
'user_id' => int 1
'conversations_id' => int 90
'messages' =>
array (size=27)
0 =>
...
1 =>
...
...
26 =>
array (size=7)
'id' => int 816
'user_id' => int 1
'conv_id' => int 90
'body' => string 'test1' (length=5)
'created_at' => string '2014-07-03 01:13:35' (length=19)
'updated_at' => string '2014-07-03 01:13:35' (length=19)
'microseconds' => string '1404350015499' (length=13)
Expected result
array (size=7)
'id' => int 90
'name' => string 'haha,hehe' (length=9)
'created_at' => string '2014-07-03 15:04:04' (length=19)
'updated_at' => string '2014-07-03 15:04:04' (length=19)
'microseconds' => string '1404370893302' (length=13)
'pivot' =>
array (size=2)
'user_id' => int 1
'conversations_id' => int 90
'messages' =>
array (size=1)
0 =>
array (size=7)
'id' => int 816
'user_id' => int 1
'conv_id' => int 90
'body' => string 'test1' (length=5)
'created_at' => string '2014-07-03 01:13:35' (length=19)
'updated_at' => string '2014-07-03 01:13:35' (length=19)
'microseconds' => string '1404350015499' (length=13)
回答1:
When you put get
(or first
/find
etc for that matter) in the closure it runs the query once more, but that query is ignored, and then Eloquent executes that query again:
$user->load(['conversations' => function($q)
{
$q->orderBy('created_at', 'desc');
$q->with('Messages')->orderBy('created_at','desc')
->get() // this query is executed here
->first(); // this calls first method on the collection
// but those 2 lines above take no effect with the eager load models
// because Eloquent will execute the query again in the end
}]);
This is how you put constraints on the nested relation (but it won't do the job here):
User::with(['conversations.messages' => function ($q) {
$q->orderBy(...)->where(...) ...;
// but limit(1) can't be used here
}])->get();
Limit
can't be used because it limits the whole set to 1, so there will be only 1 message returned in total. That said, only 1 conversation will have loaded single message in a collection.. Totally wrong
So the only way to achieve this with Eloquent
is this 'helper' relation:
// Conversation model
public function latestMessage()
{
return $this->hasOne('Message')->latest();
}
// then simply:
$user->load('conversations.latestMessage');
$user->conversations->first()->latestMessage; // single Message model
回答2:
Try using;
User::with('conversations', 'conversions.messages')
And with that you can add your eager loading contraints with a closure like;
User::with(array('conversations' => function(){}, 'conversions.messages' => function(){})
Be aware this is not tested.
来源:https://stackoverflow.com/questions/24550295/laravel-4-in-nested-relationship-how-do-i-eager-load-and-retrieve-just-the-fi