34
votes

I would like to sort a populated Document from the collection i fetch, i get an error requesting it.

Let's admit a Document Group (Group) and 'Member' (Group.Members)

Group
  .find({})
  .populate('Members')

Works perfectly, but i would like to sort it so i do this:

Group
  .find({})
  .populate('Members', ['_id', 'name'], null, { sort: [[ 'created_at', 'desc' ]] })

I get the error TypeError: Invalid select() argument. Must be a string or object. by adding this...

6

6 Answers

70
votes

You can also explicitly specify only required parameters of populate:

Group
  .find({})
  .populate({path: 'Members', options: { sort: { 'created_at': -1 } } })

Have a look at http://mongoosejs.com/docs/api.html#document_Document-populate

25
votes

This example above works with Mongoose 2.x and above, use this syntax:

Group
  .find({})
  .populate('Members', '_id name', null, { sort: { 'created_at': -1 } })
16
votes

And for Mongoose 4.x use this syntax:

Kitten.find().populate({
    path: 'owner'
  , select: 'name'
  , match: { color: 'black' }
  , options: { sort: { name: -1 }}
}).exec(function (err, kittens) {
  console.log(kittens[0].owner.name) // Zoopa
})

// alternatively
Kitten.find().populate('owner', 'name', null, {sort: { name: -1 }}).exec(function (err, kittens) {
  console.log(kittens[0].owner.name) // Zoopa
})

Reference: Mongoose docs

7
votes

This worked correctly for me in Mongoose Versions 5 and above.

Clinics.findById(req.params.id).populate({path:'users',options:{ sort:{date : 1}}}).exec(callback);
2
votes

The following worked for me in Mongoose v5.0.5:

    Schedule.find({})
        .populate({path: 'eventComments', options: {sort:{"commentDate": "descending"}}})
        .exec(function(err, result) {
            if (err) {
                throw err
            } 

            else {
                return res.json(result);
            }
    });

P.S. The key difference between this example and the Kitten example is that commentDate is in quotes, whereas Date (in the Kitten example) is not. This alteration may be necessary for some of you. Hope this helps.

0
votes

I ended up needing to populate a nested document, this worked for me:

const video = await Video.findOne({ urlId }) // find video
        .populate('likes user') // populate the likes and owner (user) of video
        .populate({
            path: 'comments', // populate the comments as well,
            options: { sort: { date: -1 } }, // sorting the comments by date
            populate: {
                path: 'user', // and populating the owner (user) of each comment,
                select: 'username, date', // plucking whichever fields necessary from the User model
            },
        })
]);