given this fantasy dataset (sorry in advance but I couldn't manage to format it properly):
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)
$type
and "missing" (the right way to go if you wanted only exists), here you want null, also so it becomes bigger query$ifnull
this is the shortest way$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
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",
""
]
}
}
}
])