0

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.

7
  • 1
    I'm not sure how messages.dateViewd: -1 is interpreted, I would suggest at least adding quotes, just to be sure everything's fine there :) Commented Mar 21, 2016 at 17:40
  • @AndreyPopov Yes, I've changed it to {"messages.dateViewed": -1, "messages.dateSent": -1}, but it still doesn't work... Commented Mar 21, 2016 at 17:54
  • Possible duplicate of Mongodb: sort documents by array objects Commented Mar 21, 2016 at 20:45
  • Another possible duplicate stackoverflow.com/questions/28889240/… Commented Mar 21, 2016 at 20:50
  • Possible duplicate of Sort the array in the document with MongoDB Commented Mar 21, 2016 at 21:10

1 Answer 1

1

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 } ] }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.