有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
}
我需要从具有特定标题的集合等级电影中选择所有项目[电影收藏的条件]。我如何实现这一目标?
答案 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()