Перемотать дважды после размотки дважды - PullRequest
1 голос
/ 11 марта 2020

У меня есть документ в 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
     ]
}

Я также пытаюсь найти в таблице пользователей все данные об авторах, используя сохраненные идентификаторы присоединен.

Вот мой код прямо сейчас:

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

И я получаю эту ошибку

pymon go .errors.OperationFailure: Проект агрегации оператор не поддерживается: '$ pu sh'

Я хочу получить:

{
     "_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?

Ответы [ 2 ]

1 голос
/ 12 марта 2020

pymon go .errors.OperationFailure: оператор проекта агрегации не поддерживается: '$ pu sh'

Это потому, что у вас есть вложенный $push. Если вы ввели этот конвейер агрегации в оболочке mon go, вы должны получить следующее сообщение об ошибке:

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

Это связано с тем, что вложенная операция должна быть выражение агрегации , но $push не является оператором выражения.

Что мне нужно изменить в моем запросе MongoDB?

Чтобы использовать $ group после $ unwind на самом деле немного анти-паттерна. Я бы порекомендовал использовать $ map и $ lower Например:

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.

0 голосов
/ 12 марта 2020

После нескольких часов писанины с моим кодом я пришел к этому коду, который дает мне нужный результат.

[
   {
      "$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 step, чтобы перемотать вложенный массив обратно. Надеюсь, что это поможет любому, кто столкнется с подобной потребностью в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...