根据对孩子中父母的参考来查找文档

时间:2017-07-05 05:00:33

标签: javascript node.js mongodb mongoose mongodb-query

有2个系列电影排名电影。这2个系列引用关系

Movie model

var mongoose = require('mongoose');

var movieSchema = new mongoose.Schema({
    m_tmdb_id: {
        type: Number,
        unique: true,
        index: true
    },
    m_adult: {
        type: Boolean
    },
    m_backdrop_path: {
        type: String,
    },
    m_title: {
        type: Number
    },
    m_genres: {
        type: Array
    }

});
var MovieModel = mongoose.model('Movie', movieSchema);
module.exports = {
    movie: MovieModel
}

Rank movie model

var mongoose = require('mongoose');
var rankMovieSchema = new mongoose.Schema({
    movie: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Movie',
        unique: true
    },
    rank: {
        type: Number
    },
    count: {
        type: Number
    }
});
var RankMovieModel = mongoose.model('RankMovie', rankMovieSchema);
module.exports = {
    rankmovie: RankMovieModel
}

我需要从具有特定标题的集合等级电影中选择所有项目[电影收藏的条件]。我如何实现这一目标?

1 个答案:

答案 0 :(得分:2)

实际上,执行此操作的“最佳”方法是使用.aggregate()$lookup来“加入”数据并“匹配”匹配条件。这非常有效,因为与.populate()发出“多个”查询相比,MongoDB实际上在“服务器”本身上执行了所有这些操作。

MovieModel.aggregate([
  { "$match": { "m_title": m_title } },
  { "$lookup": {
    "from": RankMovieModel.collection.name,
    "localField": "_id",
    "foreignField": "movie",
    "as": "rankings"
  }}
])
  

注意: RankMovieModel.collection.name是从Mongoose注册的Model获取“基础”集合名称的好方法。由于操作在“服务器”上,因此MongoDB需要“真实的集合名称”,因此我们可以“硬编码”或者只是从模型本身注册的信息中获取它。就像在这里一样。

如果有很多排名,那么您最好使用$unwind,这将为每个相关的“排名”项目创建一个文档:

MovieModel.aggregate([
  { "$match": { "m_title": m_title } },
  { "$lookup": {
    "from": RankMovieModel.collection.name,
    "localField": "_id",
    "foreignField": "movie",
    "as": "rankings"
  }},
  { "$unwind": "$rankings" }
])

此处还有一个特殊的处理方式,即MongoDB如何处理“加入”文档以避免违反16MB BSON限制。所以事实上,当$unwind直接跟随$lookup管道阶段时,会发生这种特殊情况:

    {
        "$lookup" : {
            "from" : "rankmovies",
            "as" : "rankings",
            "localField" : "_id",
            "foreignField" : "movie",
            "unwinding" : {
                "preserveNullAndEmptyArrays" : false
            }
        }
    }

所以$unwind实际上“消失”,而是“卷起”到$lookup本身,好像这是“一个”操作。这样我们就不会在父文档中直接创建一个“数组”,这会导致在大多数“相关”项目的极端情况下大小超过16MB。

如果您没有支持$lookup的MongoDB( MongoDB 3.2 minunum ),那么您可以使用带有.populate()的“虚拟”(需要Mongoose)最低4.5.0 )。但请注意,这实际上会对服务器执行“两个”查询:

首先将“虚拟”添加到架构中:

movieSchema.virtual("rankings",{
  "ref": "Movie",
  "localField": "_id",
  "foreignField": "movie"
});

然后使用.populate()发出查询:

MovieModel.find({ "m_title": m_title })
  .populate('rankings')
  .exec()