How to add fields to output conditionally (dynamically)

Hey everyone. I have a trouble of aggregation of heterogeneous objects from the one collection. For example:

    {
    "id": "google.com/q=blah",
    "type": "url",
    "domain": "google.com"
    "key_id": 123
    },
    {
    "id": "google.com/q=blah",
    "domain": "google.com"
    "type": "url",
    "key_id": 321
    },
    {
    "id": "google.com"
    "type": "domain",
    "key_id": 123,
    "registred": True,
    },
    {
    "id": "google.com"
    "type": "domain",
    "key_id": 321,
    "registred": True,
    }

My intention here is to merge objects that have the same “id” objects:

    $group: {
         _id: "$id",
        "key_ids": {"$addToSet": "$key_id"},
        "type": {"$last": "$type"}
       "domain": {"$last": "$domain"}
    },
    $project: {
        "id": "$_id",
        "keys_ids": "$key_ids",
        "type": "$type",
       "domain": "$domain"
    }

This strategy works well when the query is filtered by “type” field and all objects have the same field set.

When I have in the query output multiple types with different set of fields I don’t know how do I check if field exists and add it to project.
Is it possible generally with Mongo?

Hello, @Alex_G! Welcome to the community!

You can match documents with missing field like this:

{
  $match: {
    fieldA: {
      $exists: false,
    },
  },
},

In the $project stage you can unify the fields set by adding a fallback value for missing fields, like this:

{
  $project: {
    fieldB: {
      $cond: {
        // if fieldB is not present in the document (missing)
        if: {
          $eq: [{ $type: '$fieldB' }, 'missing'],
        },
        // then set it to some fallback value
        then: 'Field is missing',
        // else return it as is
      else: '$fieldB',
      },
    },
  },
},

In $project stage, if you try to include or exclude non-existent field for all documents, the pipeline will not break. So, if you want to exclude some specific field, but you are not sure if it is present in the document - don’t overthink, just exclude it :slight_smile:

{
  $project: {
    unwantedFieldA: false,
    mayBeMissingFieldB: false,
  }
}

You can conditionally exclude the field with $$REMOVE variable

{
  $project: {
    contidionalField: {
      $cond: {
        if: {
          $eq: ['$filedA', 'abc'],
        },
        // then return its value as is
        then: '$fieldA',
        // else exclude this field
        else: '$$REMOVE',
      },
    },
  },
},
1 Like

Hi Slava,

thanks a lot for your answer.

$cond: {
if: {
$eq: [‘$filedA’, ‘abc’],
},
// then return its value as is
then: ‘$fieldA’,
// else exclude this field
else: ‘$$REMOVE’,
},

is exactly what I looked for.
Cheers!

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