简体   繁体   English

mongodb / mongoose聚合结合了两个表/集合

[英]mongodb/mongoose aggregation that combine two table/collection

I am using mLab for database and mongoose in node js.I am using swagger which should not cause any problem. 我在节点js中使用mLab来存储数据库和猫鼬,我正在使用swagger这应该不会造成任何问题。 I have following schemas. 我有以下架构。 when user request, I need to return movie and review together if (review = true) in query. 当用户请求时,如果查询中(review = true),我需要返回电影并一起查看。 One movie may have multiple reviews. 一部电影可能有多个评论。 first, I have to find all the movies in the database. 首先,我必须在数据库中查找所有电影。 when I find movies, I have to go through each of them, look for any reviews in another database and somehow attach them in movie. 当我找到电影时,我必须仔细阅读每个电影,在另一个数据库中查找任何评论,然后以某种方式将它们附加在电影中。 I need to return all the movies in one package because it will be used in getAll fucntion. 我需要将所有电影放回一个包中,因为它将用于getAll功能。 No matter what I do it only returning movies without reviews. 不管我做什么,只返回没有评论的电影。

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

res.send is called before the db reviews result is received: 在收到数据库评论结果之前调用res.send:

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

You can use promises to wait for the results. 您可以使用Promise等待结果。 I'll give an example with async/await. 我将以async / await为例。 Using promises without async/await is also an option. 也可以使用不带异步/等待的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);
    });
  });
}

This could need some tweaks as I have not tested it. 由于我尚未测试,因此可能需要进行一些调整。 I hope it gives the general idea of how to fix the issue. 我希望它能给出解决此问题的总体思路。

Without async/await you can call the promises and run ".then" to process the results. 如果没有异步/等待,则可以调用promises并运行“ .then”以处理结果。 If you haven't used promises a few google searches should help understand how .then works. 如果您没有使用诺言,那么一些Google搜索应该可以帮助您了解.then的工作方式。

First thank you @curtwphillips however, I have found short way to do this. 首先,谢谢@curtwphillips,但我发现这样做的捷径。 But for this to work, movie and review have to in same database as different collection. 但是,要使此工作正常进行,电影和评论必须与不同收藏集放在同一数据库中。 If you use different database, it doesn't work 如果您使用其他数据库,则无法使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM