API 在聚合中使用多个 $lookup 时需要很长时间才能响应

API taking much time to response when using mulitiple $lookup in aggregation

我正在使用下面的代码获取用户对话

对话模式

const conversationSchema = new Schema({
    userIdSender: {
        type: Schema.Types.ObjectId,
        ref: 'user',
    },
    userIdReceiver: {
        type: Schema.Types.ObjectId,
        ref: 'user',
    },
    isRead: {
        type: Boolean,
        default: false,
    },
    isEmailSent: {
        type: Boolean,
        default: false,
    },
    readPendingFrom: {
        type: String,
        default: ''
    },
    dateCreated: {
        type: Date,
    },
    dateUpdated: {
        type: Date,
    },
    isDeleted: {
        type: Number,
        default: 0,
    },
})

在我的用户模式中,我有一个“isBlocked”字段。我正在尝试获取“isBlocked”为假的用户之间的所有对话。我正在使用以下聚合来实现这一点。

const conversationPipeline: any = [
                 {
                     $match: {
                         '$or': [
                             {
                                 'userIdReceiver': userDetailsFromToken._id,
                             },
                             {
                                 'userIdSender': userDetailsFromToken._id,
                             }
                         ],
                     }
                 },
                 {
                     $lookup: {
                         from: 'users',
                         localField: 'userIdReceiver',
                         foreignField: '_id',
                         as: 'userReveiver'
                     }
                 },
                 { $unwind: '$userReveiver' },
                 { $match: { 'userReveiver.isBlocked': false } },
                 {
                     $lookup: {
                         from: 'users',
                         localField: 'userIdSender',
                         foreignField: '_id',
                         as: 'userSender'
                     }
                 },
                 { $unwind: '$userSender' },
                 { $match: { 'userSender.isBlocked': false } },
                 {
                     $project: {
                         _id: 1,
                         dateUpdated: 1,
                         isRead: 1,
                         readPendingFrom: { $ifNull: ['$readPendingFrom', ''] },
                         userIdSender: 1,
                         flag: {
                             $cond: [
                                 {$eq: ['$readPendingFrom' , String(userDetailsFromToken?._id)]},
                                 1,
                                 0
                             ]
                         },
                         userIdReceiver: 1,
                         senderBlockList: { $ifNull: ['$senderConnections.userBlockList', []] },
                         receiverBlockList: { $ifNull: ['$receiverConnections.userBlockList', []] }
                     }
                 },
                 {$sort:{flag:-1,dateUpdated:-1}},
                 { $skip: Number(offset) || 0 },
                 { $limit: Number(limit) || 20 }
             ]

我收到以下想要的回复

 "data": {
        "message": "OK",
        "count": 142226,
        "conversations": [
            {
                "receiverUser": {
                    "profilePicUrl": "",
                    "isBlocked": false,
                    "_id": "0000",
                    "firstName": "Demo",
                    "lastName": "Demo",
                    "username": "Demo_Demo",
                    "dateUpdated": "2022-02-14T01:37:03.123Z",
                    "userConnectionId": {
                        "userNetworks": [],
                        "pendingRequests": [],
                        "sentRequests": [],
                        "userBlockList": [],
                        "isDeleted": 0,
                        "_id": "0000",
                        "userId": "0000",
                        "dateCreated": "2022-02-14T01:34:17.539Z",
                        "dateUpdated": "2022-02-14T01:34:17.539Z",
                        "__v": 0
                    }
                },
                "senderUser": {
                    "profilePicUrl": "1/profile_photo_4365136bb203ab.jpg",
                    "isBlocked": false,
                    "_id": "123",
                    "firstName": "Tea",
                    "lastName": "Tdsadeam",
                    "username": "arsdatmo",
                    "dateUpdated": "2022-02-14T01:55:05.571Z",
                    "userConnectionId": {
                        "userNetworks": [
                           
                        ],
                        "pendingRequests": [],
                        "sentRequests": [],
                        "userBlockList": [],
                        "isDeleted": 0,
                        "_id": "123",
                        "userId": "123",
                        "__v": 0,
                        "dateUpdated": "2022-02-10T17:53:03.285Z",
                        "oldUserConnectionId": "1"
                    }
                },
                "_id": "6209b199cc39c2001dd4d003",
                "dateUpdated": "2022-02-14T01:40:06.846Z",
                "isRead": false,
                "readPendingFrom": "0000",
                "senderBlockList": [],
                "receiverBlockList": []
            }
        ],
        "chatThreadExist": false,
        "userNotExist": null
    }

使用上面的查询我可以得到想要的结果,但是 api 获取数据的时间太长了。 有什么办法可以优化上面的代码吗

这是一个骨架聚合管道,它使用单个 "$lookup""$match" 来排除 "isBlocked": true 用户。希望这就足够了,这样您就可以了解如何将类似的东西合并到您的聚合管道中……并希望它更有效率。

db.conversations.aggregate([
  { // select sender or receiver
    $match: {
      "$or": [
        { "userIdReceiver": 16 },
        { "userIdSender": 16 }
      ]
    }
  },
  { // lookup the users
    "$lookup": {
      "from": "users",
      "let": {
        "userIdSender": "$userIdSender",
        "userIdReceiver": "$userIdReceiver"
      },
      "pipeline": [
        { // only need this conversation's users
          "$match": {
            "$expr": {
              "$in": [
                "$_id",
                [ "$$userIdSender", "$$userIdReceiver" ]
              ]
            }
          }
        },
        { // only care if they are blocked
          "$project": {
            "_id": 0,
            "isBlocked": 1
          }
        }
      ],
      "as": "blockTest"
    }
  },
  { // eliminate conversations where either user is blocked
    "$match": {
      "$expr": { "$or": "$blockTest.isBlocked" }
    }
  },
  { // don't need lookup info anymore
    "$unset": "blockTest"
  }
])

mongoplayground.net 上试用。