Обратный вызов NodeJS после нескольких асинхронных функций в цикле for - PullRequest
0 голосов
/ 20 декабря 2018

Я получаю документ от mongodb, который содержит массив с комментариями к этому документу.В комментарии указан _id пользователя, который написал комментарий.

Теперь мне нужно получить имя пользователя на основе _id пользователя, но я столкнулся с несколькими проблемами.

У меня есть следующий код, который, очевидно, не работает,но я надеюсь, что это может дать вам представление о том, чего я пытаюсь достичь.

//MORE CODE... (No need to show this here, just a promise, some try catch and so on)
let article = await Article.findOne({_id:articleid})   
    for(var i = 0; i<=article.comment.length-1; i++){
        User.findOne({_id:article.comment[i].user}).then((user)=>{
            article.comment[i].username = user.username
        })
    }
return resolve(article)

Я просмотрел несколько документов, но не смог найти работающего решения.Я попытался использовать Promise.all, поиграл с большим количеством асинхронных, ожидающих, попытался добавить счетчик в цикл for и разрешить обещание после завершения цикла, но пока ничего не получалось.

Вот как выглядит статья в моей базе данных:

{
    "_id" : ObjectId("5c18c1cbc47e5e29d42e4b0e"),
    "completed" : false,
    "completedAt" : null,
    "comment" : [ 
        {
            "_id" : ObjectId("5c18c95e328c8319ac07d817"),
            "comment" : "This is a comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }, 
        {
            "_id" : ObjectId("5c18fb578de5741f20a4e2bd"),
            "comment" : "Another comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }
    ]
}

Я довольно плохо знаком с nodejs и mongodb, так что я надеюсь, что вы сможете помочь новичку, как я.

Спасибо за вашу помощь

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Здесь можно использовать несколько подходов, исходя из вашего удобства

Использование асинхронного ожидания

let article = await Article.findOne({ _id: articleid }).lean().exec()

await Promise.all(
  article.comment.map(async(obj) => {
    const user = await User.findOne({ _id: obj.user })
    obj.username = user.username
  })
)

console.log(article)

Использование $lookup агрегация 3,6

Поскольку mongodb имеет собственный мощный $lookup оператор агрегирования для объединения нескольких коллекций и, возможно, лучший подход без какой-либо итерации

Article.aggregate([
  { "$match": { "_id": mongoose.Types.ObjectId(articleid) }},
  { "$unwind": "$comment" },
  { "$lookup": {
    "from": "users",
    "let": { "userId": "$comment.user" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": ["$$userId", "$_id"] }}}
    ],
    "as": "comment.user"
  }},
  { "$unwind": "$comment.user" },
  { "$group": {
    "_id": "$_id",
    "comment": { "$push": "$comment" },
    "completed": { "$first": "$completed" },
    "completedAt": { "$first": "$completedAt" }
  }}
])

Использование $lookup агрегация 3,4

Article.aggregate([
  { "$match": { "_id": mongoose.Types.ObjectId(articleid) }},
  { "$unwind": "$comment" },
  { "$lookup": {
    "from": "users",
    "localField": "comment.user",
    "foreignField": "_id",
    "as": "comment.user"
  }}
  { "$unwind": "$comment.user" },
  { "$group": {
    "_id": "$_id",
    "comment": { "$push": "$comment" },
    "completed": { "$first": "$completed" },
    "completedAt": { "$first": "$completedAt" }
  }}
])
0 голосов
/ 20 декабря 2018

Вы можете попробовать следующим образом

const d = {
    "_id" : ObjectId("5c18c1cbc47e5e29d42e4b0e"),
    "completed" : false,
    "completedAt" : null,
    "comment" : [ 
        {
            "_id" : ObjectId("5c18c95e328c8319ac07d817"),
            "comment" : "This is a comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }, 
        {
            "_id" : ObjectId("5c18fb578de5741f20a4e2bd"),
            "comment" : "Another comment",
            "rating" : [ ],
            "user" : ObjectId("5c18b76e73236d2168eda2b4")
        }
    ]
}

d.comment.forEach( async (obj, index) => {
    await new Promise((res) => {
            obj.counter = index;
            res();
    })
});

console.log(d);

Для справки, пожалуйста, посмотрите по следующей ссылке Asycn / Await с использованием forEach

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