展开两次后倒回两次

Rewind twice after unwinding twice

我在 MongoDB 中有一份文件,我正在尝试展开它。我想展开带有 comments 字段的文档,然后展开每个评论中的 replies 字段。之后我需要把它倒回去。

所以文档结构是这样的:

{
     "_id": <some_id>,
     "post_body": "test post",
     "author_id": <some_user_id>,
     "comments": [
          {
              "comment_body": "comment test",
              "comment_author_id": <some_user_id>,
              "replies": [
                   {
                       "reply_body": "reply test",
                       "reply_author_id": <some_user_id>
                   },
                   ... more items
              ]
          },
          ... more items
     ]
}

我也在尝试使用附加的已保存 ID 从用户 table 查找所有作者数据。

这是我现在的代码:

            {
                "$match": {"post_id": post_id}
            },
            {
                "$lookup": {
                    "from": "usersLookup",
                    "localField": "author_id",
                    "foreignField": "_id",
                    "as": "author_data"
                }
            },
            {
                "$unwind": {
                    "path": "$comments",
                    "preserveNullAndEmptyArrays": True
                }
            },
            {
                "$lookup": {
                    "from": "usersLookup",
                    "localField": "comments.comment_author_id",
                    "foreignField": "_id",
                    "as": "comment_author_data"
                }
            },
            {
                "$unwind": {
                    "path": "$comments.replies",
                    "preserveNullAndEmptyArrays": True
                }
            },
            {
                "$lookup": {
                    "from": "usersLookup",
                    "localField": "comments.replies.reply_author_id",
                    "foreignField": "_id",
                    "as": "reply_author_data"
                }
            },
            {
                "$group": {
                    "_id": '$_id',
                    "post_body": {"$first": "$post_body"},
                    "author": {"$first": "$authorData"},
                    "comments": {
                        "$push": {
                            "comment_body": "$comments.comment_body",
                            "comment_author_data": "$comment_author_data",
                            "replies": {
                                "$push": {
                                    "reply_body": "$comments.replies.reply_body",
                                    "reply_author_data": "$reply_author_data"
                                }
                            }
                        }
                    }
                }
            }

我收到这个错误

pymongo.errors.OperationFailure: Aggregation project operator not supported: '$push'

我想得到:

{
     "_id": <some_id>,
     "post_body": "test post",
     "author_data": {"author_name": "test1"},
     "comments": [
          {
              "comment_body": "comment test",
              "comment_author_data": {"author_name": "test1"},
              "replies": [
                   {
                       "reply_body": "reply test",
                       "reply_author_data": {"author_name": "test1"}
                   },
                   ... more items
              ]
          },
          ... more items
     ]
}

我的 MongoDB 查询需要更改什么?

pymongo.errors.OperationFailure: Aggregation project operator not supported: '$push'

这是因为您有一个嵌套的 $push。如果您在 mongo shell 中输入此聚合管道,您应该会收到以下错误消息:

  "errmsg": "Unrecognized expression '$push'",

这是因为嵌套运算应该是 aggregation expression,但 $push 不是表达式运算符。

What do I need to change in my MongoDB query?

使用$group after $unwind is actually a bit of anti-pattern. I'd recommend using $map and $reduce。例如:

db.collection.aggregate([
            {
                "$lookup": {
                    "from": "usersLookup",
                    "localField": "author_id",
                    "foreignField": "_id",
                    "as": "author_data"
                }
            },
            {
                "$lookup": {
                    "from": "usersLookup",
                    "localField": "comments.comment_author_id",
                    "foreignField": "_id",
                    "as": "comment_author_data"
                }
            },
            {
                "$lookup": {
                    "from": "usersLookup",
                    "localField": "comments.replies.reply_author_id",
                    "foreignField": "_id",
                    "as": "reply_author_data"
                }
            },
            {"$addFields": {
                "author_data": {
                    "$reduce": {
                        "input":"$author_data", 
                        "initialValue": "",
                        "in": "$$this"
                    }
                },
                "comments": {
                    "$map": {
                        "input": "$comments",
                        "as": "c",
                        "in": {
                            "comment_author_id": "$$c.comment_author_id",
                            "comment_body": "$$c.comment_body",
                            "comment_author_data": {
                                "$arrayElemAt": [
                                    "$comment_author_data",
                                    { "$indexOfArray": [ "$comment_author_data._id", "$$c.comment_author_id" ] }
                                ]
                            },
                            "replies": {
                                "$map":{
                                    "input": "$$c.replies", 
                                    "as": "r", 
                                    "in":{
                                        "reply_body":"$$r.reply_body", 
                                        "reply_author_id":"$$r.reply_author_id", 
                                        "reply_author_data":{
                                            "$arrayElemAt": [
                                                "$reply_author_data", 
                                                {"$indexOfArray": ["$reply_author_data._id", "$$r.reply_author_id"] }
                                            ]
                                        }
                                    }
                                }
                            }
                        }
                    }
                }, 
            }}, 
            {"$project": {
                "author_data._id":0,
                "comment_author_data":0, 
                "comments.comment_author_data._id":0,
                "reply_author_data":0, 
                "comments.replies.reply_author_data._id":0
            }}
])

上面应该解析来自 $lookup 的嵌套数组结果,而不使用 $unwind$group。上面的聚合管道示例是在 MongoDB v4.2.

中编写的

经过数小时的代码乱写,我得到了这段代码,它给出了我需要的结果。

[
   {
      "$match":{
         "post_id":"post_id"
      }
   },
   {
      "$lookup":{
         "from":"usersLookup",
         "localField":"author_id",
         "foreignField":"_id",
         "as":"author_data"
      }
   },
   {
      "$unwind":{
         "path":"$comments",
         "preserveNullAndEmptyArrays":True
      }
   },
   {
      "$lookup":{
         "from":"usersLookup",
         "localField":"comments.comment_author_id",
         "foreignField":"_id",
         "as":"comment_author_data"
      }
   },
   {
      "$unwind":{
         "path":"$comments.replies",
         "preserveNullAndEmptyArrays":True
      }
   },
   {
      "$lookup":{
         "from":"usersLookup",
         "localField":"comments.replies.reply_author_id",
         "foreignField":"_id",
         "as":"reply_author_data"
      }
   },
   {
      "$group":{
         "_id":{
            "_id":"$_id",
            "author":"$author_data",
            "post_body":"$post_body",
            "comment_body":"$comments.comment_body",
            "comment_author_data":"$comment_author_data"
         },
         "replies":{
            "$push":{
               "reply_body":"$comments.replies.reply_body",
               "reply_author_data":"$reply_author_data"
            }
         }
      }
   },
   {
      "$group":{
         "_id":"$_id._id",
         "post_body":{
            "$first":"$_id.post_body"
         },
         "author_data":{
            "$first":"$_id.author"
         },
         "comments":{
            "$push":{
               "comment_body":"$_id.comment_body",
               "comment_author_data":"$_id.comment_author_data",
               "replies":"$replies"
            }
         }
      }
   }
]

我不得不使用 $group 步两次来倒回嵌套数组。希望这对以后遇到类似需求的任何人有所帮助。