postsArr n'obtient pas de données

  router.get('/user-post/:id', checkJwt, (req, res, next) => {
  let postsArr = []
  db.userSchema.findOne({ _id: req.params.id })
    .populate('posts')
    .exec((err, da) => {
      for (let i = 0; i < da.posts.length; i++) {
        db.postSchema.find({ _id: da.posts[i]._id })
          .populate('comments')
          .exec((err, post) => {
            postsArr.push(post)
          })
      }
      console.log(postsArr)
    })

})
0
rabie_alkholi 13 mars 2021 à 13:19

1 réponse

Meilleure réponse

C'est beaucoup plus facile si vous utilisez l'interface de promesse sur votre base de données:

router.get('/user-post/:id', checkJwt, async (req, res, next) => {
    try {
        let da = await db.userSchema.findOne({ _id: req.params.id }).populate('posts').exec();
        let postsArray = await Promise.all(da.posts.map(post => {
            return db.postSchema.find({ _id: post._id }).populate('comments').exec();
        }));
        res.json(postsArray);
    } catch (e) {
        console.log(e);
        res.sendStatus(500):
    }
});

Le défi avec une opération asynchrone dans une boucle est qu'elles ne s'exécutent pas séquentiellement - elles s'exécutent toutes en parallèle. La boucle for démarre simplement toutes vos opérations asynchrones et vous ne savez jamais quand elles sont toutes terminées à moins que vous ne les suiviez toutes d'une manière ou d'une autre. Cela peut être fait sans promesses en utilisant des compteurs pour savoir quand chaque résultat asynchrone est fait, mais il est beaucoup plus facile de laisser Promise.all() le faire pour vous. Il mettra également tous les résultats dans le bon ordre pour vous aussi.


Si vous souhaitez séquencer les opérations de base de données et les exécuter en série une par une, vous pouvez le faire:

router.get('/user-post/:id', checkJwt, async (req, res, next) => {
    try {
        let da = await db.userSchema.findOne({ _id: req.params.id }).populate('posts').exec();
        let postsArray = [];
        for (let post of da.posts) {
            let result = await db.postSchema.find({ _id: post._id }).populate('comments').exec();
            postsArray.push(result);
        }
        res.json(postsArray);
    } catch (e) {
        console.log(e);
        res.sendStatus(500):
    }
});

Cette deuxième version exécute une seule opération de base de données à la fois, de manière séquentielle. Cela mettra moins de charge de pointe sur la base de données, mais sera probablement plus lent à terminer.


Vous remarquerez que l'utilisation de promesses et await rend la gestion des erreurs beaucoup plus simple car toutes les erreurs se propageront au même try/catch où vous pouvez enregistrer l'erreur et envoyer une réponse d'erreur. Votre code d'origine n'a pas eu de gestion des erreurs sur vos appels DB.

1
jfriend00 13 mars 2021 à 10:56