Есть 2 коллекции Movie и Rank Movie. Эти 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
}
Мне нужно выбрать все элементы из фильма ранга коллекции, имеющие определенный заголовок [Условие в коллекции фильмов]. Как я могу это достичь?
На самом деле "лучший" способ сделать это скорее использует .aggregate()
и $lookup
для "объединения" данных и "фильтрации" в условиях соответствия. Это очень эффективно, так как MongoDB фактически выполняет все это на самом "сервере" по сравнению с выдачей "множественных" запросов как .populate()
.
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}}
])
Примечание.
RankMovieModel.collection.name
- отличный способ получить название базовойRankMovieModel.collection.name
изModel
зарегистрированной в Mongoose. Поскольку операция находится на "сервере", MongoDB нуждается в "реальном имени коллекции", поэтому мы можем либо "жестко", либо просто получить его от информации, зарегистрированной на самой модели. Как это делается здесь.
Если есть "партии" ранжирования, то лучше всего использовать $unwind
, который создаст документ для каждого связанного элемента "рейтинг":
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
Существует также особый подход к тому, как MongoDB занимается "присоединением" документов, чтобы не нарушать предел BSON на 16 МБ. Так ведь это особая вещь происходит, когда $unwind
непосредственно следует за $lookup
этапа трубопровода:
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
Таким образом, $unwind
фактически "исчезает" и вместо этого "свернут" в самом $lookup
, как если бы это была "одна" операция. Таким образом, мы не создаем "массив" непосредственно в родительском документе, который в крайних случаях может превышать 16 МБ со многими "связанными" элементами.
Если у вас нет MongoDB, который поддерживает $lookup
(MongoDB 3.2 minunum), тогда вы можете использовать "virtual" с .populate()
вместо этого (требуется минимум Mongoose 4.5.0). Но обратите внимание, что это фактически выполняет "два" запроса на сервер:
Сначала добавьте "виртуальную" в схему:
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Затем выполните запрос с помощью .populate()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()