8

I have a very simple mongo scheme I'm accessing with mongoose

I can map the username and firstname to each notification's from field by using populate, the issue is I can't seem to get any sorting to work on the date field

With this code I get an error of

MongooseError: Cannot populate with sort on path notifications.from because it is a subproperty of a document array

Is it possible to do this a different way, or newer way (deep populate, virtuals)? I'm on Mongoose 5.

I'd rather not use vanilla javascript to sort the object afterwards or create a separate schema

var UserSchema = new Schema({  
    username: String,
    firstname: String,
    notifications: [
        {  
            from: { type: Schema.Types.ObjectId, ref: 'User'},
            date: Date,
            desc: String
        }
    ]
});

app.get('/notifications', function(req, res) {
    User.findOne({ _id: req._id }, 'notifications')
    .populate({
        path: 'notifications.from',   
        populate: {
            path: 'from',
            model: 'User',
            options: { sort: { 'notifications.date': -1 } }            
        }
    }) 
    .exec(function(err, user) {
        if (err) console.log(err)
    })
});

That possible duplicate is almost 2 years old about Mongo. I'm asking if there are newer or different ways of doing this in Mongoose as it has changed a bit since 2016 with newer features.

Taki
  • 17,320
  • 4
  • 26
  • 47
totalnoob
  • 2,521
  • 8
  • 35
  • 69
  • Possible duplicate of [How to sort sub-documents in the array field?](https://stackoverflow.com/questions/36875995/how-to-sort-sub-documents-in-the-array-field) – HRK44 Mar 15 '18 at 16:09
  • That possible duplicate is almost 2 years old about Mongo. I'm asking if there are newer or different ways of doing this in Mongoose -- as it has changed a bit since 2016 with newer features. – totalnoob Mar 15 '18 at 16:11

2 Answers2

3

From Mongoose V5.0.12 FAQ : http://mongoosejs.com/docs/faq.html#populate_sort_order

Q. I'm populating a nested property under an array like the below code:

new Schema({ arr: [{ child: { ref: 'OtherModel', type: Schema.Types.ObjectId } }] });

.populate({ path: 'arr.child', options: { sort: 'name' } }) won't sort by arr.child.name?

A. See this GitHub issue. It's a known issue but one that's exceptionally difficult to fix.

So unfortunately, for now, it's not possible,

One way to achieve this is to simply use javascript's native sort to sort the notifications after fetching.

.exec(function(err, user) {
    if (err) console.log(err)

    user.notifications.sort(function(a, b){ 
        return new Date(b.date) - new Date(a.date);
    });

})
Taki
  • 17,320
  • 4
  • 26
  • 47
  • won't that be an issue when one would lazy load with pagination? – totalnoob Apr 09 '18 at 13:44
  • no, `.sort()` only sorts the result you're getting from the database, it does the same thing that `sort: { 'notifications.date': -1 }` would do ( without `populate` ), it doesn't change the data. – Taki Apr 09 '18 at 13:55
0
It can be achievable using nesting populate like this - 

eg - schema - {donationHistory: {campaignRequestId: [ref ids]}}

await user.populate({
        path: 'donationHistory.campaignRequestId',
        populate: [{
            path: 'campaignRequestId',
            model: 'CampaignRequest',
            options: { sort: { 'createdAt': -1 } },
        }],
        ...deepUserPopulation,
    }).execPopulate();
Shivam Pandey
  • 94
  • 2
  • 1