Home > OS >  MongoDb - checking existence of param in array during $addFields
MongoDb - checking existence of param in array during $addFields

Time:09-25

given this fantasy dataset (sorry in advance but I couldn't manage to format it properly):

enter image description here

I would need to make a MongoDb pipe where a new field is created and, this new field, should be able to add a parameter valued with an empty string whene the "k" parameter is missing or empty.

Here is my attempt:

...    
{
    "$addFields": {
        "colors_field": {
            "r": "$colors.r",
            "g": "$colors.g",
            "b": "$colors.b",
            "k": {
                "$cond": {
                    "if": {
                       "$or": [
                            {"$eq": [ "$colors.k", "" ]},
                            {"$eq": [ "$colors.k", null ]},
                            {"$colors.k": { "$exists": false}}
                            ]
                    },
                    "then": "",
                    "else": "$colors.k"
                }
            }
        }
    }
}

I tried with the $exists but I can't make it work because of the way I call the value to check: either I put "$colors.k" and it returns a "MongoError: Unrecognized expression" or I don't and it'll return a "MongoError: FieldPath field names may not contain '.'". I also tried to check for the length of that field but it'll crash if said field is missing.

CodePudding user response:

The problem with your query is that you are using a query operatos $exists inside a pipeline (only $match stage allows this).

We dont have an "$exists" operator in aggregation but we can do it using $type and "missing", but here you want exists or null, so $ifnull is the right way to do it(that does exaclty this,name is missleading, its if not-exists or null).

Query (3 ways to do it)

  1. $type and "missing" (the right way to go if you wanted only exists), here you want null, also so it becomes bigger query
  2. $ifnull this is the shortest way
  3. $cond not-exists or null are both false values, so this works also, BUT be careful with this, because if color was false, it would make it also ""

*in your case the short and safe solution is the 2

Test code here

db.collection.aggregate([
  {
    "$set": {
      "k-cond": {
        "$cond": [
          {
            "$or": [
              {
                "$eq": [
                  "$colors.k",
                  null
                ]
              },
              {
                "$eq": [
                  {
                    "$type": "$colors.k"
                  },
                  "missing"
                ]
              }
            ]
          },
          "",
          "$colors.k"
        ]
      },
      "k-ifnull": {
        "$ifNull": [
          "$colors.k",
          ""
        ]
      },
      "k-if": {
        "$cond": [
          "$colors.k",
          "$colors.k",
          ""
        ]
      }
    }
  }
])
  • Related