在forEach循环中运行序列化查询。无法处理结果

时间:2019-05-20 08:27:19

标签: node.js express sequelize.js

我正在运行此续集查询,该查询返回一些论坛帖子。对于每个结果,我运行第二个查询,该查询为我提供了每个论坛帖子的类别/标签。现在,forEach循环在所有查询运行之前结束,因为它是异步的,我知道那部分。如何正确处理此问题并执行我想做的事情?我想将标签/类别数组附加到每个帖子,并将帖子数组发送到ejs视图并调用next();。

我尝试了promise.all()和async-await,我确实以这种方式分别获得了类别。但我希望将类别附加到每个发布对象。

Forum.findAll({
    attributes: ["f_post_id", "f_post_title", "like_count", "createdAt"],
    limit: limitPost.FORUM,
    subQuery: false,
    raw: true,
    group: ['forum.f_post_title'],

    include: [{
        attributes: ["user_name"],
        model: User,
        required: true, // returns everything in a clean single object format
                        // setting it to false, results in nested arrays
    }, {
        attributes: [[Sequelize.fn("COUNT", Sequelize.col("forum_answers.answer_id")), "ansCount"]],
        model: ForumAnswer,
        required: true,
    }]
})
    .then(fetchedPost => {

        fetchedPost.forEach(post => {

            ForumTag.findAll({
                attributes: [],
                raw: true,

                where: {
                    f_post_id: post.f_post_id,
                },
                include: [{
                    attributes: ["tag_name"],
                    model: Tag,
                    required: true,
                }]
            })
                .then(postTags => {

                    post.tags = postTags.map(postTag => postTag["tag.tag_name"]);

                })
                .catch(err => console.log(err));

        });

        res.locals.fetchedPost = fetchedPost;
        next();

    })
    .catch(err => console.log(err));

这是下面的预期结果:

{ 
  f_post_id: 1,
  f_post_title: 'learn js',
  like_count: 12,
  createdAt: 2019-05-19T00:00:00.000Z,
  'user.user_name': 'mrscx',
  'forum_answers.ansCount': 3,
  tags: [ 'JavaScript', 'Database' ] 
}

但是因为forEach循环结束,所以未附加标签。

我该如何解决?

2 个答案:

答案 0 :(得分:0)

findAll()调用是异步的,因此forEach为每个帖子调用ForumTag.findAll(),但是在修改生效之前立即返回。另外,您需要在修改后在模型上调用save()方法以使其永久(例如post.save()之后的post.tags = ...

您可以尝试这样的事情:

let promises = [];

fetchedPost.forEach(post => {

  ForumTag.findAll({
    attributes: [],
    raw: true,

    where: {
      f_post_id: post.f_post_id,
    },
    include: [{
      attributes: ["tag_name"],
      model: Tag,
      required: true,
    }]
  })
    .then(postTags => {

       post.tags = postTags.map(postTag => postTag["tag.tag_name"]);
       promises.push(post.save());

  })
    .catch(err => console.log(err));

});

Promise.all(promises).then(() => {
  res.locals.fetchedPost = fetchedPost;
  next();
}).catch(err => {
  throw err;
});

答案 1 :(得分:0)

从外观上看,问题可能出在您处理承诺的方式上。您实际上并不是在等待forEach循环中的promise,而是在此之前返回结果。解决该问题的一种方法是:

Forum.findAll({
    attributes: ["f_post_id", "f_post_title", "like_count", "createdAt"],
    limit: limitPost.FORUM,
    subQuery: false,
    raw: true,
    group: ['forum.f_post_title'],

    include: [{
        attributes: ["user_name"],
        model: User,
        required: true, // returns everything in a clean single object format
                        // setting it to false, results in nested arrays
    }, {
        attributes: [[Sequelize.fn("COUNT", Sequelize.col("forum_answers.answer_id")), "ansCount"]],
        model: ForumAnswer,
        required: true,
    }]
})
    .then(fetchedPost => {

        return Promise.all(fetchedPost.map(post => 
            ForumTag.findAll({
                attributes: [],
                raw: true,

                where: {
                    f_post_id: post.f_post_id,
                },
                include: [{
                    attributes: ["tag_name"],
                    model: Tag,
                    required: true,
                }]
            })
                .then(postTags => {

                    post.tags = postTags.map(postTag => postTag["tag.tag_name"]);
                    return post.save();
                })
                .catch(err => console.log(err));

        }).then(() => {
          res.locals.fetchedPost = fetchedPost;
          next();
      });
    })

我敢肯定,还有更优雅的方法可以做这种事情。但这是对原始代码的最少修改。