javascript - 根据对子项中父项的引用查找文档

标签 javascript node.js mongodb mongoose mongodb-query

MovieRank Movie 2个合集。这2个合集有引用关系

电影模型

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
}

电影排名模型

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
}

我需要从具有特定标题[电影收藏条件]的收藏等级电影中选择所有项目。我怎样才能做到这一点?

最佳答案

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

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

Note: The RankMovieModel.collection.name is a nice way of getting the "underlying" collection name from the Model registered with Mongoose. Since the operation is on the "server", MongoDB needs the "real collection name", so we can either "hardcode" that or just get it from the information registered on the Model itself. As is done here.

如果有“很多”的排名,那么你最好使用$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()

关于javascript - 根据对子项中父项的引用查找文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44917336/

相关文章:

javascript - 是否可以在 TypeScript 中使用类型化流?

node.js - moment.js 反转 .fromNow()

javascript - MongoDB 从聚合中排除某些文档

c# - 如何在mongodb中选择嵌套文档?

ruby - Mongoid:根据嵌入文档数组的大小进行查询

javascript - 获取不在数组中的值

javascript - 如何避免声音管理器2中的声音延迟

javascript - Javascript 中的去抖动不适用于滚轮事件

javascript - JS中克隆对象时的"New"关键字

javascript - 如何在整个应用程序中访问配置对象?