1

I'm having a problem using $lookup in my aggregation pipeline.

I have 2 collections, members & messages

members :

{_id, FirstName, LastName, Email, ...}

messages

{
  _id:ObjectId('xxx'),
  createdBy:ObjectId(''),
  ...
  threads:[
    {  message:'' , attachments:[] , from:ObjectId , to:[{status:'Read' , recipient:ObjectId}] }]
}

What I'm trying to do is,

lookup for each recipient in : to:[{status:'Read' , recipient:ObjectId}] and populate name and email from members collection.

I tried many different things like this one; //

db.messages.aggregate([
     {
                '$lookup': {
                    'from': 'members',
                    'let': {
                        'memberId': '$threads.to.recipient'
                    },
                    'pipeline': [
                        {
                            '$match': {
                                '$expr': {
                                    '$eq': [
                                        '$$memberId', '$members._id'
                                    ]
                                }
                            }
                        },
                        {$project: {FirstName: 1, _id: 1, LastName: 1, Email: 1}}
                    ],
                    'as': 'members'
                }
            }
    ]

Many different queries including this one always return [] for members ('as': 'members').

Just to test I tired with mongoose and .populate('threads.to.recipient','FirstName') worked perfectly. But I cannot use mongoose for this I have to use MongoDB's native nodejs driver.

any advice would be greatly appreciated on this...

1
  • Please add sample data in mongo shell-executable format. Commented Oct 14, 2020 at 3:17

1 Answer 1

2

You have to use $unwind to flatten the structure of threads array before performing $lookup

db.messages.aggregate([
  {
    $unwind: "$threads"
  },
  {
    $unwind: "$threads.to"
  },
  {
    $lookup: {
      from: "members",
      let: {
        memberId: "$threads.to.recipient"
      },
      as: "members",
      pipeline: [
        {
          $match: {
            $expr: {
              $eq: [
                "$$memberId",
                "$_id"
              ]
            }
          }
        },
        {
          $project: {
            FirstName: 1,
            _id: 1,
            LastName: 1,
            Email: 1
          }
        }
      ]
    }
  }
])

See the working example in MongoDB Playground

If you don't want to use $unwind, just try the below query:

db.messages.aggregate([
  {
    "$lookup": {
      "from": "members",
      "localField": "threads.to.recipient",
      "foreignField": "_id",
      "as": "members"
    }
  }
])

See the working example in MongoDB Playground

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, flatten the structure of threads worked. I have to use $unwind since simple lookup with localField & foreignField does not let me project fields from members.

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.