There are 2 collections Movie and Rank Movie .This 2 collections having referenced relationship .
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
}
I need to select all the items from the collection rank movie having a particular title[Condition on movie collection ].How can i achieve this?
Actually the "best" way to do this is rather using .aggregate()
and $lookup
to "join" the data and "filter" on the match conditions. This is very effective since MongoDB actually performs all of this on the "server" itself, as compared to issuing "multiple" queries as .populate()
does.
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.
If there are "lots" of rankings, then you are best to use $unwind
, which will create a document for each related "rankings" item:
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
There is also a special handling here of how MongoDB deals with "joining" documents to avoid breaching the 16MB BSON limit. So in fact this special thing happens when $unwind
directly follows a $lookup
pipeline stage:
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
So the $unwind
actually "disappears" and instead is "rolled-up" into the $lookup
itself as if this were "one" operation. That way we do not create an "array" directly within the parent document which would cause the size to exceed 16MB in extreme cases with many "related" items.
If you do not have a MongoDB that supports $lookup
( MongoDB 3.2 minunum ) then you could use a "virtual" with .populate()
instead (requires Mongoose 4.5.0 minimum). But note this actually performs "two" queries to the server:
First add the "virtual" to the schema:
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Then issue the query with .populate()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()