billy
billy

Reputation: 11

Mongoose how can I get a list of conversations, a sepcific user has chatted with?

Ok, so basically my data model looks like this:

var messageSchema = new Schema({
    to: { type: String, required: true},
    from: { type: String, required: true},
    message: { type: String, required: true}
});

What I want to do is have a function I can just pass in the username of the current logged in user: example billy.

The database might contain 100's of messages like this:

[{"_id":"2394290384","from":"billy","to":"dan","message":"some message"},
 {"_id":"2394290384","from":"dan","to":"billy","message":"some message"},
 {"_id":"2394290389","from":"john","to":"billy","message":"some message"},
 {"_id":"2394290389","from":"billy","to":"john","message":"some message"}] 

It should just give me an output like this:

 [{"_id":"2394290384","from":"billy","to":"dan","message":"some message"},   
  {"_id":"2394290389","from":"john","to":"billy","message":"some message"}] 

How can I just pull the latest 1 for each of those messages.

So it basically shows 1 result per conversation / person I have had a chat with regardless of if I sent them a message or they sent me a message.

It should just pull up 1 result per conversation with the all the data related to their latest message.

So the latest message, the id for that message, the user it was to and from.

So that I can create a conversation list on 1 side which shows the users and their message below their name. the user clicks on it and it shows the chat.

I have asked multiple variations of this question trying to figure it out and I have been un successful so far in finding a solution for this.

I come from a php mysql background so I am new to node and mongoose.

Thank you for all your help in advance I really appreciate it.

I have already mentioned why the 2 items in the example are distinct. It is pulling 1 result per conversation based on the current logged in username.

So there needs to be a function like this:

getconversations(username){
Message.find(Where messages are to this username or from this from username).exec(function(error,results){
this would probably output all messages like so:
[{"_id":"2394290384","from":"billy","to":"dan","message":"some message"},
 {"_id":"2394290384","from":"dan","to":"billy","message":"some message"},
 {"_id":"2394290389","from":"john","to":"billy","message":"some message"},
 {"_id":"2394290389","from":"billy","to":"john","message":"some message"}] 


})
}

if the current username was billy.

    But I only want 1 of the latest.

    So i can have a list on the left:
    messages:
    username:
    lastmessage
    username:
    last message

    a user clicks on it and it opens up the full chat. For example like you see on skype on ios or android: it shows you a list of users and their message below. you tap on it and it shows you the chat. it is basically pulling that list based on people you have had a conversation with.

How I finally got it working:

var user="billy";
Message.aggregate(
    {
           $match: {
              $or: [{
                to: user
              }, 
              {
                from: user
              }]
            }
        },
    { $project: { "from" : {
      $cond: {'if': {$eq: ['$to',user]},'then': '$from', 'else': '$to'}
                            },
                            "to":{
      $cond: {'if': {$eq: ['$to',user]},'then': '$to', 'else': '$from'}
                            },
                            "message":"$message"



                } },
    { $sort: { _id: -1 } },
    { $group: { "id": { "$first" : "$_id" },"_id" : { "from" : "$from" }, "from": { "$first" : "$from" },"to": { "$first" : "$to" }, "message": { "$first" : "$message" }  } }
, function(err, docs) {
  res.send(docs);

});

It searches by a specific username and strips all duplicates and just outputs the 1 record per user and outputs their message, id, to and from

Upvotes: 1

Views: 1501

Answers (1)

moonthug
moonthug

Reputation: 406

I assume the question is how do you perform an or query in Mongodb from Mongoose?

var Message = mongoose.model('message');
Message.find({ $or: [ { from: 'billy' }, { to: 'billy' } ] }, function(err, docs) {
    // docs will now be an array of Message models
});

Update: You can order by _id as its based on time inserted and then limit results to one record:

var Message = mongoose.model('message');
Message.find({ $or: [ { from: 'billy' }, { to: 'billy' } ] })
    .sort({ _id : -1 })
    .limit(1)
    .exec(function(err, docs) {
    // docs will now be an array containing 1 Message model
});

Update 2:
Try using the aggregation framework:

var Message = mongoose.model('message');
Message.aggregate(
    { $project: { "from" : "$from", "message" : "$message" } },
    { $sort: { _id: -1 } },
    { $group: { "_id" : { "from" : "$from" }, "from": { "$first" : "$from" }, "message": { "$first" : "$message" } } }
, function(err, docs) {
    /* i.e. docs = array
    [ 
        { "_id" : { "from" : "alex" }, "from" : "alex", "message" : "Some message" },
        { "_id" : { "from" : "billy" }, "from" : "billy", "message" : "Some message" },
    ...

    */
});

Upvotes: 1

Related Questions