Mongoose, sort query by populated field Mongoose, sort query by populated field mongoose mongoose

Mongoose, sort query by populated field


You can explicitly specify only required parameters of populate method:

WizardModel  .find({})  .populate({path: 'spells', options: { sort: [['damages', 'asc']] }})

Have a look at http://mongoosejs.com/docs/api.html#document_Document-populateHere is an example from a link above.

doc.populate('company').populate({  path: 'notes',  match: /airline/,  select: 'text',  model: 'modelName'  options: opts}, function (err, user) {  assert(doc._id == user._id) // the document itself is passed})


Even though this is rather an old post, I'd like to share a solution through the MongoDB aggregation lookup pipeline

The important part is this:

 {      $lookup: {        from: 'spells',        localField: 'spells',        foreignField:'_id',        as: 'spells'      }    },    {      $project: {        _id: 1,        name: 1,        // project the values from damages in the spells array in a new array called damages        damages: '$spells.damages',        spells: {          name: 1,          damages: 1        }      }    },    // take the maximum damage from the damages array    {      $project: {        _id: 1,        spells: 1,        name: 1,        maxDamage: {$max: '$damages'}      }    },    // do the sorting    {      $sort: {'maxDamage' : -1}    }

Find below a complete example

'use strict';const mongoose = require('mongoose');const Schema = mongoose.Schema;mongoose.connect('mongodb://localhost/lotr');const db = mongoose.connection;db.on('error', console.error.bind(console, 'connection error:'));db.once('open', () => {  let SpellSchema = new Schema({    name    : { type: String },    damages : { type: Number }  });  let Spell = mongoose.model('Spell', SpellSchema);  let WizardSchema = new Schema({    name: { type: String },    spells: [{ type: Schema.Types.ObjectId, ref: 'Spell' }]  });  let Wizard = mongoose.model('Wizard', WizardSchema);  let fireball = new Spell({    name: 'Fireball',    damages: 20  });  let frozenball = new Spell({    name: 'Frozenball',    damages: 10  });  let lightball = new Spell({    name: 'Lightball',    damages: 15  });  let spells = [fireball, frozenball, lightball];  let wizards = [{    name: 'Gandalf',    spells:[fireball]  }, {    name: 'Saruman',    spells:[frozenball]  }, {    name: 'Radagast',    spells:[lightball]  }];  let aggregation = [    {      $match: {}    },    // find all spells in the spells collection related to wizards and fill populate into wizards.spells    {      $lookup: {        from: 'spells',        localField: 'spells',        foreignField:'_id',        as: 'spells'      }    },    {      $project: {        _id: 1,        name: 1,        // project the values from damages in the spells array in a new array called damages        damages: '$spells.damages',        spells: {          name: 1,          damages: 1        }      }    },    // take the maximum damage from the damages array    {      $project: {        _id: 1,        spells: 1,        name: 1,        maxDamage: {$max: '$damages'}      }    },    // do the sorting    {      $sort: {'maxDamage' : -1}    }  ];  Spell.create(spells, (err, spells) => {    if (err) throw(err);    else {      Wizard.create(wizards, (err, wizards) =>{        if (err) throw(err);        else {          Wizard.aggregate(aggregation)          .exec((err, models) => {            if (err) throw(err);            else {              console.log(models[0]); // eslint-disable-line              console.log(models[1]); // eslint-disable-line              console.log(models[2]); // eslint-disable-line              Wizard.remove().exec(() => {                Spell.remove().exec(() => {                  process.exit(0);                });              });            }          });        }      });    }  });});


Ask yourself(and here are the answers):

What I want?Sort wizards by their spell damage(it should be an aditional field, probably the sum of the spells damage.

What I did:I have sorted the SPELLS of the wizard.

What should you do:Wizard.find({}).sort({ power : 'asc' }) and then populate with spells and do whatever you like.Power is another field in Wizard. You will need it because even if you populate your spells, you will have an array of spells and it won't help you.

Hope this helps.