Joum
Joum

Reputation: 3245

mongoose sort by dates from array

I have a Chat model which has a messages array which holds Messages. Each Message has both a dateSent property and a dateViewed property. The Message items are embedded, not referenced.

How can I sort Chats by most recent not viewed Message (ie, empty dateViewed) first and then by dateSent? (think Facebook Messenger behavior...)

This is what I've tried so far (note that Chat also has a users array):

Chat.find({users._id: userId}).sort({messages.dateViewed: -1, messages.dateSent: -1}).exec(function(err, chats){
    // handle err
    // handle no docs found
    // handle docs found
});

The above does not seem to work, as the Chats come out in a different order (the same as without sort()). Any thoughts?

EDIT: The suggested answer didn't help me because I don't want to sort the Message objects in the message array, but rather sort the Chats resulting from the query, by the dates in the Message object they hold in a messages array.

Upvotes: 0

Views: 1105

Answers (1)

DraganS
DraganS

Reputation: 2699

The Aggregation pipeline should be used in order to achieve the required sort.

chats/messages:

> db.chats.find()
{ "_id" : "c1", "messages" : [ { "_id" : "m1_1", "dv" : -1, "ds" : 9000 }, { "_id" : "m1_2", "dv" : 8010, "ds" : 8000 } ] }
{ "_id" : "c2", "messages" : [ { "_id" : "m2_1", "dv" : -1, "ds" : 11000 } ] }
{ "_id" : "c3", "messages" : [ { "_id" : "m3_1", "dv" : -1, "ds" : 700 }, { "_id" : "m3_2", "dv" : 7010, "ds" : 7000 } ] }

The code to sort the data by the give criteria:

db.chats.aggregate([
{ $unwind: '$messages' },
{ $addFields: { 
        ts: { 
            $cond: [ 
                { $eq: ['$messages.dv', -1 ] }, 
                '$messages.ds', 
                '$messages.dv']
        }
    }
}, 
{ 
    $sort: { 'ts': -1 }
}, 
{     
    $group: {
        _id: '$_id',
        ts: { $max: '$ts'},
        messages: { $push: '$messages' }     
    }
}, 
{ 
    $sort: {ts: -1}
}]);

The results:

{ "_id" : "c2", "ts" : 11000, "messages" : [ { "_id" : "m2_1", "dv" : -1, "ds" : 11000 } ] }
{ "_id" : "c1", "ts" : 9000, "messages" : [ { "_id" : "m1_1", "dv" : -1, "ds" : 9000 }, { "_id" : "m1_2", "dv" : 8010, "ds" : 8000 } ] }
{ "_id" : "c3", "ts" : 7010, "messages" : [ { "_id" : "m3_2", "dv" : 7010, "ds" : 7000 }, { "_id" : "m3_1", "dv" : -1, "ds" : 700 } ] }

Upvotes: 1

Related Questions