1

我在 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 从用户表中查找所有作者数据。

这是我现在的代码:

            {
                "$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:不支持聚合项目运算符:'$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 查询中进行哪些更改?

4

2 回答 2

1

pymongo.errors.OperationFailure:不支持聚合项目运算符:'$push'

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

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

这是因为嵌套操作应为聚合表达式,但$push不是表达式运算符。

我需要在 MongoDB 查询中进行哪些更改?

在$unwind之后使用$group实际上有点反模式。我建议使用$map$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的嵌套数组结果,而不使用$unwindand $group。上面的聚合管道示例是用 MongoDB v4.2 编写的。

于 2020-03-12T00:15:09.547 回答
0

在用我的代码写了几个小时后,我得到了这个代码,它给了我需要的结果。

[
   {
      "$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"
            }
         }
      }
   }
]

我不得不使用$groupstep 两次来回退嵌套数组。希望这对将来偶然发现类似需求的任何人有所帮助。

于 2020-03-12T02:23:00.233 回答