I have the following query:
cursor=self.postCol.aggregate([
{ "$graphLookup" : {
"from": "pCol",
"startWith": "$parent",
"connectFromField": "parent",
"connectToField": "_id",
"as" : "parents"
}
},
{ "$project" : {
"pValue": {
"$cond": [
{ "$ne": [ "$pValue", [] ] },
"$pValue",
"$parents.0.pValue"
]
}
}
}
])
so given then following records:
{"_id": 4, parent: "", "pValue": ["d"], fieldA: 9},
{"_id": 5, parent: 4, "pValue": [], fieldA:2},
{"_id": 6, parent: 4,"pValue": [], fieldA: 9}
I should get:
{"_id": 4, "pValue": ["d"]}
{"_id": 5, "pValue": ["d"]}
{"_id": 6, "pValue": ["d"]}
Instead I get:
{"_id": 4, "pValue": ["d"]}
{"_id": 5, "pValue": []}
{"_id": 6, "pValue": []}
The $parents.0.pValue isn't returning the right value for some reason which I don't understand. How can I select the field of pValue within the first element of the parents array?
I thought to use {"$arrayElemAt": ["$parents",0]} which will give me the embedded document but then how can I then get a field from that to be returned?
You can replace the else condition with below using $let operator.
{
$let: {
vars: {
obj: {
"$arrayElemAt": ["$parents", 0]
}
},
in: "$$obj.pValue"
}
}
You can use the $switch operator and the $let operator to $project your field.
The $let variable operator let you assign a value to a variable which can be used in the "in" expression as shown in my other answer here.
With the $switch operator, we can perform very clean case-statement.
db.postCol.aggregate([
{ "$graphLookup": {
"from": "postCol",
"startWith": "$parent",
"connectFromField": "parent",
"connectToField": "_id",
"as" : "parents"
}},
{ "$project": {
"pValue": {
"$switch": {
"branches": [
{ "case": { "$gt": [ { "$size": "$pValue"}, 0 ] },
"then": "$pValue" }
],
"default": {
"$let": {
"vars": { "p": { "$arrayElemAt": [ "$parents", 0 ] }},
"in": "$$p.pValue"
}
}
}
}
}}
])