Home > Back-end >  Merge Names From Data For Message Application
Merge Names From Data For Message Application

Time:10-30

Hello guys I'm writing a Message Application with Node.js and Mongoose. I keep datas in mongodb like that:

enter image description here

I want to list users who messaged before so I need to filter my 'Messages' collection but I can't do what exactly I want. If he sent a message to a person I need to take persons name but, if he take a message from a person I need to take persons name however in first situation person name in reciever, in second situation person name in sender. I made a table for explain more easily. I have left table and I need 3 name like second table.(Need to eliminate one John's name)

enter image description here

Sorry, if this problem asked before but I don't know how can I search this problem.

I tried this but it take user name who logged in and duplicate some names.

Message.find({$or: [{sender: req.user.username}, {reciever: req.user.username}]})

CodePudding user response:

This is a tricky one, but can be solved with a fairly simple aggregation pipeline.

Explanation

On our first stage of the pipeline, we will want to get all the messages sent or received by the user (in our case David), for that we will use a $match stage:

{
  $match: {
    $or: [
      {sender: 'David'},
      {receiver: 'David'}
    ]
  }
}

After we found all the messages from or to David, we can start collecting the people he talks to, for that we will use a $group stage and use 2 operations that will help us to achieve this:

  • $addToSet - This will add all the names to a set. Sets only contain one instance of the same value and ignore any other instance trying to be added to the set of the same value.
  • $cond - This will be used to add either the receiver or the sender, depending which one of them is David.

The stage will look like this:

{
  $group: {
    _id: null,
    chats: {$addToSet: {$cond: {
      if: {$eq: ['$sender', 'David']},
      then: '$receiver',
      else: '$sender'
    }}}
  }
}

Combining these 2 stages together will give us the expected result, one document looking like this:

{
  "_id": null, // We don't care about this
  "chats": [
    "John",
    "James",
    "Daniel"
  ]
}

Final Solution

Message.aggregate([{
 $match: {
  $or: [
   {
    sender: req.user.username
   },
   {
    receiver: req.user.username
   }
  ]
 }
}, {
 $group: {
  _id: null,
  chats: {
   $addToSet: {
    $cond: {
     'if': {
      $eq: [
       '$sender',
       req.user.username
      ]
     },
     then: '$receiver',
     'else': '$sender'
    }
   }
  }
 }
}])

Sources

CodePudding user response:

One option is to use an aggregation pipeline to create to sets and simply union them:

db.collection.aggregate([
  {$match: {$or: [{sender: req.user.username}, {reciever: req.user.username}]}},
  {$group: {
      _id: 0,
      recievers: {$addToSet: "$reciever"},
      senders: {$addToSet: "$sender"}
  }},
  {$project: {
      _id: req.user.username,
      previousChats: {"$setDifference": 
        [
          {$setUnion: ["$recievers", "$senders"]},
          [req.user.username]
        ]
      }
  }}
])

See how it works on the playground example

  • Related