0

I want to use $lookup in the aggregate method. The collection I want to do this is like this. It is an array. It has nested objects in the array.

Please notice my problem is with the lookup and the way I want to get my data. The names of the properties are not so important, the important property is "position_id".

[
  {
    name : 'projectName1',
    positions : [
      {
        position_id : id1,
        use : true,
        wage : 0,
        default : true
      },
      {
        position_id : id2,
        use : true,
        wage : 0,
        default : true
      }          
    ]
  }      
]

When I lookup on the "position_id" like this:

$lookup: {
  from: 'positions',
  localField: 'positions.position_id',
  foreignField: '_id',        
  as: 'positions.positionDetails'
}

The result is:

"positions": {
    "positionDetails": [
        {
            "_id": "63d78e5096109914dc963431",
            "field": "electrical",
            "regularName": "elc",
        },
        {
            "_id": "63d78e5096109914dc963433",
            "field": "mechanic",
            "regularName": "mec",
        }
    ]
}

The positions array was changed to an object.

But I want to get data like this :

"positions": [
    {
        "position_id": "63d78e5096109914dc963431",
        "use": true,
        "default": true,
        "wage": 0,
        "positionDetails" : {
            "field": "electrical",
            "regularName": "elc",
        }
    },
    {
        "position_id": "63d78e5096109914dc963433",
        "use": true,
        "default": false,
        "wage": 0,
        "positionDetails" : {
            "field": "mechanic",
            "regularName": "mec",
        }
    }
]

1 Answer 1

1
  1. $lookup - Join with positions collection for the document into positionDetails field.

  2. $set - Set positions field.

    2.1. $map - Iterate each document in positions array and return a new array.

    2.1.1. $mergeObjects - Merge the current iterate document from the positions array with the result from 2.1.1.1.

    2.1.1.1. $first - Get the first matched element from the result 2.1.1.1.1 and assign it to the positionDetails field in the new document.

    2.1.1.1.1. $filter - Filter the elements from the positionDetails array which match the id.

  3. $unset - Remove positionDetails array field.

db.doc.aggregate([
  {
    $lookup: {
      from: "positions",
      localField: "positions.position_id",
      foreignField: "_id",
      as: "positionDetails"
    }
  },
  {
    $set: {
      positions: {
        $map: {
          input: "$positions",
          as: "pos",
          in: {
            $mergeObjects: [
              "$$pos",
              {
                "positionDetails": {
                  $first: {
                    $filter: {
                      input: "$positionDetails",
                      cond: {
                        $eq: [
                          "$$pos.position_id",
                          "$$this._id"
                        ]
                      }
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    $unset: "positionDetails"
  }
])

Demo @ Mongo Playground

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

2 Comments

Thank you so much @Yong Shun . it works fine. how can I be that much expert in aggregation? I tried many ways before your answer..., I should learn more about these operators that you have used in the code.
You are mostly welcome. I also still have a long journey to be an expert. More practice and raising questions if any is the best way to improve. =D And do feel free to read StackOverflow questions & answers, there are a lot of experts to assist and give you a learning boost.

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.