Home > Back-end >  MongoDB aggregate with array and nested lookup
MongoDB aggregate with array and nested lookup

Time:11-22

I'm struggling to put a query together that aggregates the data exactly as I want. I would be so grateful if anyone can help with this!

The collections are:

Collection 1

[
 {
   "_id": 1,
   "name": "Collection 1:1",
   "collection_2_ids": [5, 6]
 },
 {
   "_id": 2,
   "name": "Collection 1:2",
   "collection_2_ids": [8, 9]
 }
]

Collection 2

[
 {
   "_id": 5,
   "name": "collection 2:5",
   "collection_1_id": 1,
   "collection_3_id": 12
 },
 {
   "_id": 6,
   "name": "collection 2:6",
   "collection_1_id": 1,
   "collection_3_id": 13
 },
 {
   "_id": 8,
   "name": "collection 2:8",
   "collection_1_id": 2,
   "collection_3_id": 14
 },
 {
   "_id": 9,
   "name": "collection 2:9",
   "collection_1_id": 2,
   "collection_3_id": 15
 },
]

Collection 3:

[
 {
   "_id": 12,
   "name": "collection 3:12"
 },
 {
   "_id": 13,
   "name": "collection 3:13"
 },
 {
   "_id": 14,
   "name": "collection 3:14"
 },
 {
   "_id": 15,
   "name": "collection 3:15"
 }
]

What I want out of it is:

[
 {
   "_id": 1,
   "name": "Collection 1:1",
   "collection_2_documents": [
     {
       "_id": 5,
       "name": "collection 2:5",
       "collection_1_id": 1,
       "collection_3_id": 12,
       "collection_3_document": {
          "_id": 12,
          "name": "collection 3:12"
        }
     },
     {
       "_id": 6,
       "name": "collection 2:6",
       "collection_1_id": 1,
       "collection_3_id": 13,
       "collection_3_document": {
          "_id": 12,
          "name": "collection 3:12"
        }
     }
  ]
 },
 {
   "_id": 2,
   "name": "Collection 1:2",
   "collection_2_documents": [
       {
       "_id": 8,
       "name": "collection 2:8",
       "collection_1_id": 2,
       "collection_3_id": 14,
       "collection_3_document": {
          "_id": 14,
          "name": "collection 3:14"
        }
     },
     {
       "_id": 9,
       "name": "collection 2:9",
       "collection_1_id": 2,
       "collection_3_id": 15,
       "collection_3_document": {
          "_id": 15,
          "name": "collection 3:15"
        }
     }
   ]
 }
]

This is the current aggregate/lookup that I have which returns separate arrays of documents from collections 2 and 3.

[  
  {
    $lookup: {
      from: 'Collection 2',
      localField: 'collection_2_ids',
      foreignField: '_id',
      as: 'collection_2_documents'
    }
  },
  {
    $lookup: {
      from: 'Collection 3',
      localField: 'collection_2_documents.collection_3_id',
      foreignField: '_id',
      as: 'collection_3_document'
    }
  }
]

CodePudding user response:

You have to make use of pipeline option of $lookup stage and use nested $lookup on collection3 inside collection2's lookup

db.collection1.aggregate([
  {
    "$lookup": {
      "from": "collection2",
      "let": {
        "sourceCollection_2_ids": "$collection_2_ids"
      },
      "pipeline": [
        {
          "$match": {
            "$expr": {
              "$in": [
                "$_id",
                "$$sourceCollection_2_ids"
              ]
            }
          }
        },
        {
          "$lookup": {
            "from": "collection3",
            "let": {
              "sourceCollection_3_id": "$collection_3_id"
            },
            "pipeline": [
              {
                "$match": {
                  "$expr": {
                    "$eq": [
                      "$_id",
                      "$$sourceCollection_3_id"
                    ]
                  },
                  
                }
              },
              
            ],
            "as": "collection_3_document"
          }
        },
        {
          "$set": {
            "collection_3_document": {
              "$arrayElemAt": [
                "$collection_3_document",
                0
              ]
            }
          }
        },
        
      ],
      "as": "collection_2_documents"
    }
  },
  
])

Mongo Playground Sample Execution

  • Related