【问题标题】:mongodb/mongoose aggregation that combine two table/collection结合两个表/集合的 mongodb/mongoose 聚合
【发布时间】:2017-04-17 01:08:27
【问题描述】:

我在节点 js 中使用 mLab 用于数据库和猫鼬。我使用的是 swagger,这不会导致任何问题。我有以下模式。当用户请求时,如果 (review = true) 在查询中,我需要一起返回电影和评论。一部电影可能有多个评论。首先,我必须找到数据库中的所有电影。当我找到电影时,我必须逐一浏览,在另一个数据库中查找任何评论,然后以某种方式将它们附加到电影中。我需要在一个包中返回所有电影,因为它将用于 getAll 功能。不管我做什么,它只会返回没有评论的电影。

var mongoose = require('mongoose');

var reviewSchema = new mongoose.Schema({
    movie:      {type: String, required: true},
    reviewer:   {type: String, required: true},
    rating:     {type: Number, required:true, min: 1, max: 5},
    text:       {type: String, required: true},
})


var movieSchema = new mongoose.Schema({
    Title:          {type: String, required: true, unique: true},
    YearReleased:   {type: Number, required: true},
    Actors:         [{
                        Name: {type: String, required: true}
    }]
})

function getAll(req,res,next){
    db.Movies.find({},function(err,movies){
        if(err) throw {err:err};
        if(req.swagger.params.review.value === false)
            res.send({Movielist: movie});
        else {
            movies.forEach(function(movie, index){
                db.Reviews.find({movie:movies[index].Title}, function (err, review) {
                    if(err) throw {err:err}
                    movies[index].Review = review    // I am trying to populate each movie with reviews
                });
            });
            res.send({Movielist: movies});
        }

    });
}

【问题讨论】:

    标签: javascript node.js asynchronous mongoose swagger-2.0


    【解决方案1】:

    res.send 在收到 db reviews 结果之前被调用:

            movies.forEach(function(movie, index){
                // this call is asynchronous, res.send will run before the callback
                db.Reviews.find({movie:movies[index].Title}, function (err, review) {
                    if(err) throw {err:err}
                    movies[index].Review = review    // I am trying to populate each movie with reviews
                });
            });
            res.send({Movielist: movies});
    

    你可以使用 Promise 来等待结果。我将举一个 async/await 的例子。使用没有 async/await 的 Promise 也是一种选择。

    async function getAll(req,res,next) {
      try {
        let movies = await getMovies();
        res.send(movies);
      } catch (err) {
        console.log(err.stack);
      }
    }
    
    async function getMovies () {
      return new Promise(function (resolve, reject) {
        db.Movies.find({},function(err,movies){
          if(err) reject(err);
          if(req.swagger.params.review.value === false)
              resolve({Movielist: movie});
          else {
            movies.forEach(function(movie, index){
              let review = await getReviews();
              movies[index].Review = review
            });
            resolve({Movielist: movies});
          }
        });
      });
    }
    
    async function getReviews (movie, index) {
      return new Promise(function (resolve, reject) {
        db.Reviews.find({movie:movies[index].Title}, function (err, review) {
            if(err) reject({err:err});
            resolve(review);
        });
      });
    }
    

    这可能需要一些调整,因为我还没有测试过。我希望它给出了如何解决这个问题的总体思路。

    如果不使用 async/await,您可以调用 Promise 并运行“.then”来处理结果。如果你没有使用过 Promise,谷歌搜索应该有助于理解 .then 的工作原理。

    【讨论】:

      【解决方案2】:

      首先谢谢@curtwphillips 但是,我找到了执行此操作的捷径。但要做到这一点,电影和评论必须在同一个数据库中作为不同的集合。如果你使用不同的数据库,它就不起作用

      function getAll(req,res,next) {
          if (req.query.review === 'true') {
              db.Movies.aggregate([
                  {
                      $lookup: {
                          from: "reviews",
                          localField: "Title",
                          foreignField: "movie",
                          as: "review"
                      }
                  }
              ], function (err, result) {
                  if (err) throw {err: err};
                  else {
                      res.send({Movielist: result});
                  }
              });
          }
          else {
              db.Movies.find({}, function (err, movies) {
                  if (err) throw {err: err};
                  res.send({Movielist: movies})
              })
          }
      }

      【讨论】:

        猜你喜欢
        • 2020-01-31
        • 2017-07-13
        • 2020-06-13
        • 1970-01-01
        • 2019-11-10
        • 2023-03-28
        • 1970-01-01
        • 2018-03-06
        • 1970-01-01
        相关资源
        最近更新 更多