我只需要获得会议室中的参与者,而不是从数据库中获取所有四个用户。 我试图以不同的方式做到这一点,但每次我从数据库表中获取所有用户。
以下是查询代码:
$data = Channel::raw(function ($collection) {
return $collection->aggregate([
[
'$match' => [
'is_default' => false,
'is_public' => false
]
],
[
'$lookup' => [
'from' => 'channel_messages',
'localField' => "ObjectId(_id)",
'foreignField' => "ObjectId(channel_id)",
'as' => "out"
]
],
[
'$unwind' => [
'path' => '$out',
'preserveNullAndEmptyArrays' => true,
]
],
[
'$unwind' => [
'path' => '$out.readBy',
'preserveNullAndEmptyArrays' => true,
]
],
[
'$lookup' => [
'from' => 'users',
'localField' => "ObjectId(participants)",
'foreignField' => "ObjectId(_id)",
'as' => "userDatas"
]
],
[
'$unwind' => [
'path' => '$userDatas',
]
],
[
'$match' => [
'userDatas' => [
'$ne' => []
]
]
],
[
'$group' => [
'_id' => [
'_id' => '$_id',
'title' => '$title',
'created_at' => '$created_at',
],
'participants' => [
'$addToSet' => '$participants',
],
'userDatas' => [
'$addToSet' => '$userDatas',
],
'unreadCount' => [
'$sum' => [
'$cond' => [
['$and' => [
'$eq' => [ '$out.readBy.recipient' , 1 ],
'$eq' => [ '$out.readBy.status' , false ]
]],
1,
0
]
]
],
'lastMessage' => [
'$last' => '$out'
]
]
],
[
'$project' => [
"_id" => '$_id._id',
'participants' => '$participants',
'userDataTotal' => [
'$size' => '$userDatas'
],
'userData' => [
'data' => '$userDatas'
],
"title" => '$_id.title',
'unread' => '$unreadCount',
'last_message' => '$lastMessage.message',
'created_at' => '$_id.created_at',
]
]
]);
});
以下是我得到的回复: https://pastebin.com/iRCJQQe6 有什么问题?
以下是三个集合中每个集合的行:https://pastebin.com/8KzW9Sv5 以下是users表中的所有行 https://pastebin.com/xDWw7gD2
答案 0 :(得分:0)
要获得正确的结果,您需要在代码中更改两件事。
首先,始终将ID引用存储为ObjectIds,而不是字符串。例如,在您的频道集合中,而不是添加如下记录:
db.channels.insert({
"_id":"5ac8f99f536c829c915ca343",
"title":"Chess",
"user_id":"5aae67c9536c8220897d9c22",
"is_public":false,
"is_default":false,
"participants" : [
"5acb7305536c82042428abe6",
"5aae67c9536c8220897d9c22"
],
"color":"#03bf00",
"created_at":"2018-04-07T17:02:23.000Z",
"updated_at":"2018-04-07T17:02:23.000Z"}
);
你应该这样做:
db.channels.insert({
"_id":ObjectId("5ac8f99f536c829c915ca343"),
"title":"Chess",
"user_id":ObjectId("5aae67c9536c8220897d9c22"),
"is_public":false,
"is_default":false,
"participants" : [
ObjectId("5acb7305536c82042428abe6"),
ObjectId("5aae67c9536c8220897d9c22")
],
"color":"#03bf00",
"created_at":"2018-04-07T17:02:23.000Z",
"updated_at":"2018-04-07T17:02:23.000Z"}
);
所有其他收藏品,'用户'和'channel_messages'也是如此。
其次,在查找阶段,更改“ObjectId(fieldname)”值并将其替换为“fieldname”,如下所示:
[
'$lookup' => [
'from' => 'users',
'localField' => "participants",
'foreignField' => "_id",
'as' => "userDatas"
]
],
它将正确执行查找并返回预期的2个用户,而不是存储在您的集合中的每个用户。
在更一般的层面上,Mongo目前不允许将ObjectIds()转换为字符串(issue SERVER-22781),尽管它可能会在将来的版本中添加。因此,如果您想要安全起见,请始终坚持查询/聚合器中的ObjectIds()。