Computing Optional Nested Field in Project Stage

I have a document with an optional nested document called operator

Document:

{
  _id: 'A',
 name: 'my name',
 operator: {
  name: 'operator A',
  website: 'www.fake.com' 
 }
}

I’d like to change this nested object to owner when querying the data. I’m doing that like so:

$project: {
 name: 1,
 'owner.name': '$operator.name',
 'owner.website': '$operator.website'
}

This works well if operator is present, my issue is that if operator is not present in the document, this query returns owner: {}

I would like to exclude the owner object completely if operator does not exist. I’d also like to specify fields within operator, as we will likely add more fields to this nested document in the future that I want automatically excluded from my query.

What would be the best way to handle this? Thanks!

Hi Greg,

You can use the $cond operator to achieve your use case, here’s the sample code -

db.collection.aggregate([
  {
    $project: {
      name: 1,
      owner: {
        $cond: {
          if: {
            $not: [
              {
                $eq: [
                  "$operator",
                  undefined
                ]
              }
            ]
          },
          // Check if operator exists
          then: {
            name: "$operator.name",
            website: "$operator.website"
          },
          else: "$$REMOVE"// Use $$REMOVE to exclude the field entirely if operator does not exist
        }
      }
    }
  }
])

Hello @Greg_Fitzpatrick-Bel, you can achieve this by following queries.

aggregationPipeline = [
  {
    $addFields: {
      owner: {
        $cond: {
          if: { $gt: [{ $ifNull: ["$operator", null] }, null] },
          then: {
            name: "$operator.name",
            website: "$operator.website"
          },
          else: "$$REMOVE"
        }
      }
    }
  },
  {
    $project: {
      name: 1,
      owner: 1
    }
  }
])

Both of these answers work, but @Akshat_Gupta3’s is more concise, so I’m marking that as the solution.

Another caveat. Although these work in mongodb directly, it doesn’t seem to work using mongoose. It seems to me that mongoose handles undefined differently or something.

I used the following in mongoose, which is less clear, but works:

{
        owner: {
          $cond: {
            if: {
              // kind of silly, but properly checks if operator is defined.
              $gt: ['$operator', null]
            },
            then: {
              name: '$operator.name',
              website: '$operator.website',
              logo: '$operator.logo'
            },
            else: '$$REMOVE'
          }
        }
}
1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.