postsArr no obtiene datos

  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 mar. 2021 a las 13:19

1 respuesta

La mejor respuesta

Esto es mucho más fácil si usa la interfaz de promesa en su base de datos:

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):
    }
});

El desafío con una operación asíncrona en un bucle es que no se ejecutan secuencialmente, todos se ejecutan en paralelo. El ciclo for simplemente inicia todas sus operaciones asincrónicas y luego nunca se sabe cuándo están todas hechas a menos que las rastree todas de alguna manera. Eso se puede hacer sin promesas usando contadores para realizar un seguimiento de cuándo se realiza cada resultado asincrónico, pero es mucho más fácil dejar que Promise.all() lo haga por usted. También pondrá todos los resultados en el orden correcto para usted.


Si desea secuenciar las operaciones de la base de datos y ejecutarlas en serie una por una, puede hacer esto:

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):
    }
});

Esta segunda versión ejecuta solo una operación de base de datos a la vez, de forma secuencial. Pondrá menos carga máxima en la base de datos, pero probablemente tardará más en finalizar.


Notará que el uso de promesas y await hace que el manejo de errores sea mucho más simple también, ya que todos los errores se propagarán al mismo try/catch donde puede registrar el error y enviar una respuesta de error. Su código original no tuvo manejo de errores en sus llamadas DB.

1
jfriend00 13 mar. 2021 a las 10:56