简体   繁体   中英

Mongoose populate query return all results with skip/limit

I have the following method in a little node/express app :

async getAll(req, res) {
    const movies = await movieModel
        .find()
        .populate({path: 'genres', select: 'name'})
        .skip(0)
        .limit(15);
    return res.send(movies);
};

With the following schema :

const MovieSchema = new mongoose.Schema({
    externalId: { required: true, type: Number },
    title: { required: true, type: String },
    genres: [{ ref: "Genre", type: mongoose.Schema.Types.ObjectId }],
    releaseDate: {type: Date},
    originalLanguage: {type : String},
    originalTitle: {type : String},
    posterPath: {type : String},
    backdropPath: {type : String},
    overview: {type: String},
    comments: [{ ref: "Comment", type: mongoose.Schema.Types.ObjectId }],
    votes: [VoteSchema]
}, {timestamps: true}
});

MovieSchema.virtual("averageNote").get(function () {
    let avg = 0;
    if (this.votes.length == 0) {
        return '-';
    }
    this.votes.forEach(vote => {
        avg += vote.note;
    });
    avg = avg / this.votes.length;
    return avg.toFixed(2);
});

MovieSchema.set("toJSON", {
    transform: (doc, ret) => {
        ret.id = ret._id;
        delete ret._id;
        delete ret.__v;
    },
    virtuals: true,
    getters: true
});

However the query always return all document entries. I also tried to add exec() at the end of the query or with .populate({path: 'genres', select: 'name', options: {skip: 0, limit: 15} }) but without result.

I tried on an other schema which is simpler and skip / limit worked just fine, so issue probably comes from my schema but I can't figure out where the problem is.

I also tried with the virtual field commented but still, limit and sort where not used.

My guess is that it's comes from votes: [VoteSchema] since it's the first time I use this, but it was recommanded by my teacher as using ref isn't recommended in a non relational database. Furthermore, in order to calculate the averageNote as a virtual field, I have no other choice.

EDIT : just tried it back with votes: [{ ref: "Vote", type: mongoose.Schema.Types.ObjectId }] And I still can't limit nor skip

Node version : 10.15.1

MongoDB version : 4.0.6

Mongoose version : 5.3.1

Let me know if I should add any other informations

This is actually more about how .populate() actually works and why the order of "chained methods" here is important. But in brief:

const movies = await movieModel
  .find()
  .skip(0)
  .limit(15)
  .populate({path: 'genres', select: 'name'}) // alternately .populate('genres','name')
  .exec()

The problem is that .populate() really just runs another query to the database to "emulate" a join . This is not really anything to do with the original .find() since all populate() does is takes the results from the query and uses certain values to "look up" documents in another collection, using that other query. Importantly the results come last .

The .skip() and .limit() on the other had are cursor modifiers and directly part of the underlying MongoDB driver. These belong to the .find() and as such these need to be in sequence

The MongoDB driver part of the builder is is forgiving in that:

.find().limit(15).skip(0)

is also acceptable due to the way the options pass in "all at once" , however it's good practice to think of it as skip then limit in that order.

Overall, the populate() method must be the last thing on the chain after any cursor modifiers such as limit() or skip() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM