MongoDB查询:未得到响应所需的结果

时间:2018-04-10 20:18:31

标签: php mongodb

我只需要获得会议室中的参与者,而不是从数据库中获取所有四个用户。 我试图以不同的方式做到这一点,但每次我从数据库表中获取所有用户。

以下是查询代码:

$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

1 个答案:

答案 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()。