GET not returning sent message. Only inbox items
You can use below aggregation to make sure that there will be only one document returned for every (recipient
, sender
) pair:
db.Messages.aggregate([ { $addFields: { conversants: [ "$recipientId", "$creator" ] } }, { $match: { conversants: req.query.recipientId } }, { $addFields: { conversant: { $arrayElemAt: [ { $filter: { input: "$conversants", cond: { $ne: [ "$$this", "5df0014e25ee451beccf588a" ] } } } , 0 ] } } }, { $sort: { creationDate: 1 } }, { $group: { _id: "$conversant", message: { $first: "$message" }, recipientId: { $first: "$recipientId" }, creator: { $first: "$creator" }, messageTrackingId: { $first: "$messageTrackingId" }, creationDate: { $first: "$creationDate" } } }, { $lookup: { from: "users", let: { creator: "$creator" }, pipeline: [ { $match: { $expr: { $eq: [ "$_id", "$$creator" ] } } }, { $project: { creatorName: 1 } } ], as: "creatorName" } }, { $addFields: { creatorName: { $arrayElemAt: [ "$creatorName", 0 ] } } }])
The idea here is that you create additional field which represents two ids: creator
and recipient
. This will allow you to do two things: filter using recipientId
(who may also be the sender) - step two, and select conversant
value which is always the second person - no matter if a person specified in your request sent or received a message in that conversation. Then you can $group
on that field to make sure that you'll get only single message in every "conversation". Instead of using $addToSet
with $arrayElemAt
you can just run $first
. Relatively heavy $lookup
can also be run as a last step since you need to get that data once per "conversant".
EDIT: first three stages can be replaced with below stages - that should significantly improve performance since the filtering will be applied as soon as possible:
{ $match: { $or: [ { recipientId: req.query.recipientId }, { creator: req.query.recipientId } ] }},{ $addFields: { conversant: { $cond: [ { $ne: [ "$recipientId", req.query.recipientId ] }, "$recipientId", "$creator" ] } }},