mongodblookup

Use a setting value from one MongoDB collection in a lookup referece in another collection aggregration


Lets' say I have a collection called settings, that has a document where the _name field has a value of A and in there there is a data.year value i.e.

"settings" : [
 { 
    _id: ObjectId('123123123123'),
    _name: "A",
    data: {
      year: 2025
    }
 }
]

I am then creating an aggregation in another collection, let's call it B, where my lookup is matching documents in A but needs to be filtered based on the year value from the settings collection document above i.e.


"B": [
  { 
    shortName: "B1"
  },
  {
    shortName: "B2"
  }
]

"A" : [
  {
    name: "A2",
    shortNameInA: "B1",
    datesInfo: {
     closed: ISODate("2025-12-10"),
    }
  },
  {
    name: "A3",
    shortNameInA: "B2",
    datesInfo: {
     report: ISODate("2025-03-10"),
    }
  },
  {
    name: "A1",
    shortNameInA: "B1",
    datesInfo: {
     closed: ISODate("2024-12-10"),
    }
  }
]

db.B.aggregate([
{
  from: "A",
  localField: "shortName",
  foreignField: "shortNameInA",
  pipeline: [
    {
      $match: {
        $expr: {
          $or: [
            {
              $eq: [
                {
                  $year: "$datesInfo.closed"
                },
                {
                  $year: "$$NOW"   <--- This needs to be `year` value from settings
                }
              ]
            },
            {
              $eq: [
                {
                  $year:
                    "$datesInfo.report"
                },
                {
                  $year: "$$NOW"  <--- This needs to be `year` value from settings
                }
              ]
            }
          ]
        }
      }
    }
  ],
  as: "_fromA"
}

What I need to do is pass in that year value instead of $$NOW - how do I do that ?

So, in this example it would pass in 2025 and I should get the following view:

[
  {   
    shortName: "B1",
    _fromA: [
     {
       name: "A2",
       shortNameInA: "B1",
       datesInfo: {
         closed: ISODate("2025-12-10"),
       }
     }
    ]
  },
  {
    shortName: "B2",
    _fromA: [
      {
        name: "A3",
        shortNameInA: "B2",
        datesInfo: {
          report: ISODate("2025-03-10"),
        }
      }
    ]
  }    
]

A full example is available here.


Solution

  • You can do a separate, unconditional$lookup to the settings collection first. Then, continue with your current $lookup by setting data.year as a variable

    db.B.aggregate([
      {
        "$lookup": {
          "from": "settings",
          "let": {
            "settingsKey": "A"
          },
          "pipeline": [
            {
              "$match": {
                $expr: {
                  $eq: [
                    "$$settingsKey",
                    "$_name"
                  ]
                }
              }
            }
          ],
          "as": "settingsLookup"
        }
      },
      {
        "$unwind": "$settingsLookup"
      },
      {
        $lookup: {
          from: "A",
          localField: "shortName",
          foreignField: "shortNameInA",
          let: {
            settingYear: "$settingsLookup.data.year"
          },
          pipeline: [
            {
              $match: {
                $expr: {
                  $or: [
                    {
                      $eq: [
                        {
                          $year: "$datesInfo.closed"
                        },
                        "$$settingYear"
                      ]
                    },
                    {
                      $eq: [
                        {
                          $year: "$datesInfo.report"
                        },
                        "$$settingYear"
                      ]
                    }
                  ]
                }
              }
            }
          ],
          as: "_fromA"
        }
      },
      {
        "$unset": "settingsLookup"
      }
    ])
    

    Mongo Playground