Как найти / заполнить вложенный документ, который находится внутри массива? - PullRequest
0 голосов
/ 15 марта 2020

Как $ искать / заполнять внедренный документ, который находится внутри массива?

Ниже показано, как выглядит моя схема.

const CommentSchema = new mongoose.Schema({
    commentText:{
        type:String,
        required: true
    },
    arrayOfReplies: [{  
        replyText:{
            type:String,
            required: true
        },
        replier: [{
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User',
            required: true,
        }],
    }],
});

Как получить результаты запроса, которые выглядят как показано ниже:

[    
    {    
        commentText: 'comment text',
        arrayOfReplies: [
            {
                replyText: 'replyText',
                replier: {
                    username:"username"
                    bio: 'bio'
                }
            }
        ]
    }
]

Я пытаюсь заполнить поле replier внутри массива arrayOfReplies. Я пробовал несколько вариантов запроса агрегации ниже. Те, кто приблизился к тому, чего я пытаюсь достичь, имеют один недостаток. Комментарии, которые не имеют ответов, имеют массив arrayOfReplies с пустым объектом. Т.е. arrayOfReplies: [{}], что означает, что массив не пуст.

Я пытался использовать add fields , $ mergeObjects среди других операторов конвейера, но безрезультатно.

Как $ искать / заполнять документ replier, который находится внутри массива arrayOfReplies?

Ниже приведен шаблон основной части моего запроса агрегации, за исключением попытки заполнить replier документ.

Comment.aggregate([
    {$unwind: {"path": '$arrayOfReplies', "preserveNullAndEmptyArrays": true }},
    {$lookup:{from:"users",localField:"$arrayOfReplies.replier",foreignField:"_id",as:"replier"}},
    {$unwind: {"path": "$replier", "preserveNullAndEmptyArrays": true }},

    {$group: {
        _id : '$_id',
        commentText:{$first: '$commentText'},
        userWhoPostedThisComment:{$first: '$userWhoPostedThisComment'},
        arrayOfReplies: {$push: '$arrayOfReplies' },
    }},

Ответы [ 3 ]

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

После этапа поиска у каждого документа будет

{
 commentText: "text",
 arrayOfReplies: <single reply, with replier ID>
 replier: [<looked up replier data>]
}

. Используйте этап $addFields, чтобы переместить эти данные респиратора внутри объекта ответа перед группой, например:

{$addFields: {"arrayOfReplies.replier":"$replier"}}

Тогда ваш групповой этап восстановит arrayOfReplies так, как вы хотите.

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

Можно использовать следующий агрегат:

Детская площадка

Comment.aggregate([
  {
    $unwind: {
      "path": "$arrayOfReplies",
      "preserveNullAndEmptyArrays": true
    }
  },
  {
    $lookup: {
      from: "users",
      localField: "arrayOfReplies.replier",
      foreignField: "_id",
      as: "replier"
    }
  },
  {
    $addFields: {
      "arrayOfReplies.replier": {
        $arrayElemAt: [
          "$replier",
          0
        ]
      }
    }
  },
  {
    $project: {
      "replier": 0
    }
  },
  {
    $group: {
      _id: "$_id",
      "arrayOfReplies": {
        "$push": "$arrayOfReplies"
      },
      commentText: {
        "$first": "$commentText"
      }
    }
  }
]);
0 голосов
/ 18 марта 2020

Все предоставленные ответы не решили эту проблему, как указано в вопросе.

Я пытаюсь заполнить поле replier внутри массива arrayOfReplies. Я пробовал несколько вариантов запроса агрегации ниже. Те, которые приблизились к тому, чего я пытаюсь достичь, имеют один недостаток. Комментарии, у которых нет ответов, имеют массив arrayOfReplies, который имеет пустой объект. Т.е. arrayOfReplies: [{}], что по сути означает, что массив не пустой.

Я хотел объединение, которое возвращает пустой массив (не массив с пустым объектом), когда массив пуст.

Мне удалось достичь того, чего я хотел, с помощью приведенного ниже кода:

 arrayOfReplies: 
     {$cond:{
         if: { $eq: ['$arrayOfReplies', {} ] },
         then: "$$REMOVE",
         else: {
                 _id : '$arrayOfReplies._id', 
                 replyText:'$arrayOfReplies.replyText',
               }
     }}

Если вы объедините приведенный выше код с ответом @ SuleymanSah , вы получите полный рабочий код.

...