"$redact": {
"$cond": {
"if": {
"$eq": [ { "$arrayElemAt": [ "$messages.type", -1 ] }, "A" ]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}
On the above code, i need to add 2 more condition in if statements but not able to add them.
i.e (messages.type = 'A' or messages.type = 'D') && (messages.sender=61)
Please help
you can use $cond with $and like this:
{$cond : [{$and : [{$eq : [1,1]},{$eq : [2,2]},{$eq : [3,3]}]},"yes","no"]}
returns "yes"
{$cond : [{$and : [{$eq : [2,1]},{$eq : [2,2]},{$eq : [3,3]}]},"yes","no"]}
returns "no"
edit:
As per the query in the OP (note this is untested):
"$redact":{
$cond : [
{
$and : [
{
$or : [
{
$eq : [
"$messages.type",
"A"
]
},
{
$eq : [
"$messages.type",
"D"
]
},
]
},
{
$eq : [
"$messages.sender",
61
]
}
]
},
"$$KEEP",
"$$PRUNE"
]
}
Related
I have a collection "structure" with a document :
{
"case" : {
"version" : 3,
"key" : 1
},
"salle" : {
"version" : 2,
"key" : 1
}
}
And I try a $cond aggregation with $ifNull operator :
db.structure.aggregate([
{
"structure" : {
"$cond": {
"if": {
"$ifNull": ["$salle", true]
},
"then": "$case.key",
"else": "$salle.key"
}
}
}
])
The trouble is that $ifNull always return true and displays $case.key, while $salle is not null
The most surprising is that I get the right response with $not operator :
db.structure.aggregate([
{
"structure" : {
"$cond": {
"if": {
"$not": {
"$ifNull": ["$salle", false]
}
},
"then": "$case.key",
"else": "$salle.key"
}
}
}
])
Can anyone can explain me what's going on ?
I want to find all documents where sCompetitions.length is greater than competitions.length.
Here's some sample documents document:
{
"_id" : ObjectId("59b28f432b4353d3f311dd1b"),
"name" : "Ford Focus RS 2008",
"requirements" : [
{
"rankType" : "D1",
"competitions" : [
ObjectId("59b151fd2b4353d3f3116827"),
ObjectId("59b151fd2b4353d3f3116829")
],
"sCompetitions" : [
"Rallye Monte-Carlo",
"Rally Sweden"
]
},
{
"rankType" : "A3",
"competitions" : [
ObjectId("59b151fd2b4353d3f3116f6b")
],
"sCompetitions" : [
"Rally Italia Sardegna",
"Neste Rally Finland"
]
}
]
},
{
"_id" : ObjectId("0000b28f432b4353f311dd1b"),
"name" : "Ford Focus RS 2012",
"requirements" : [
{
"rankType" : "D1",
"competitions" : [
ObjectId("59b151fd2b4353d3f3116827"),
ObjectId("59b151fd2b4353d3f3116829")
],
"sCompetitions" : [
"Rallye Monte-Carlo",
"Rally Sweden"
]
},
{
"rankType" : "A3",
"competitions" : [
ObjectId("59b151fd2b4353d3f3116f6b"),
ObjectId("59b151fd2b4353d3f3116f6b")
],
"sCompetitions" : [
"Rally Italia Sardegna",
"Neste Rally Finland"
]
}
]
}
So looking at the samples it would only return ObjectId("59b28f432b4353d3f311dd1b")
My problem is that requirements is an array by itself, so I would need to somehow iterate it
No need to "iterate". All you really need is an $anyElementTrue check after returning results from $map. And you can do this all inside a $redact action:
Model.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$anyElementTrue": {
"$map": {
"input": "$requirements",
"as": "r",
"in": {
"$gt": [
{ "$size": "$$r.sCompetitions" },
{ "$size": "$$r.competitions" }
]
}
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
So it's a simple comparison by $size for each array element, and then if "any" of those elements is true, the document is "kept" or otherwise "pruned" from the results.
In mongodb 3.4.5 think below simple collection ooo:
{ "id" : 1, "to" : [ { "id" : 2 }, { "id" : 4, "valid" : true } ] }
Want to $redact to if valid not true:
db.ooo.aggregate([{ "$redact": {
"$cond": {
"if": { "$ne": [ "$valid", true] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}])
Result:
{ "id" : 1, "to" : [ { "id" : 2 } ] }
But when changed condition to if valid is true:
db.ooo.aggregate([{ "$redact": {
"$cond": {
"if": { "$eq": [ "$valid", true] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}])
The result is empty.
The $redact walks the whole documents from top level then downwards, the "$valid": true part cannot pass on top level (top level have no valid field), then the $$ROOT be $$PRUNEd, and nothing returned.
The solution (skip this and see below updated):
db.ooo.aggregate([{ "$redact": {
"$cond": {
"if": { $or: ["$to", {"$eq": [ "$valid", true]}] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}])
UPDATE:
based on #neil's comment, I corrected the answer:
db.ooo.aggregate([{ "$redact": {
"$cond": {
"if": { $or: ["$to", {"$eq": [ "$valid", true]}] },
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}])
And the expected result shown:
{ "id" : 1, "to" : [ { "id" : 4, "valid" : true } ] }
That is the { "id" : 2 } be pruned.
The following query is not valid. Can anyone please point me to the error?
I am trying to filter on all documents where the last item in the Progress array has a given state - for example "Done".
db.logdata.aggregate(
[
{ "$match": { "ProcessingInfo.Progress" : { "$exists": true } } },
{ "$redact":
{
"$cond": {
"if": { "$eq": [ { "$arrayElemAt": [ "$ProcessingInfo.Progress.State", -1 ], "Done" } ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}
}
]
)
Sample document (which should be matched - because the last State in Progress array is "InProgress"):
{
"_id" : ObjectId("578fa85bb29339a1fa6d6109"),
"ProcessingInfo" : {
"DateStarted" : ISODate("2016-08-06T16:55:58.294+0000"),
"Attempt" : NumberInt(1),
"LastState" : "Failed",
"Progress" : [
{
"State" : "Failed",
"StateDescription" : ""
},
{
"State" : "Success",
"StateDescription" : ""
},
{
"State" : "Done",
"StateDescription" : ""
},
{
"State" : "InProgress",
"StateDescription" : ""
}
]
}
}
To kind of "circumvent" this problem I have an extra field in the document root "LastState" - is that maybe the way to go (complexity-wise)?
Your query has a little syntax error: your "Done" should be in the $eq array, not in the object containing $arrayElemAt definition. The following query (optimised to filter out documents without the expected State anywhere in the ProcessInfo.Progress array thanks to what Styvane suggested) should return your example document:
[
{ "$match": { "ProcessingInfo.Progress.State" : "InProgress" } },
{ "$redact":
{
"$cond": {
"if": { "$eq": [ { "$arrayElemAt": [ "$ProcessingInfo.Progress.State", -1 ] }, "InProgress" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}
}
]
How can I use $in (like) operator inside $cond? For example, inside a "project" stage I want to create a new field called "category" that is conditional on some other fields (for grouping later): it's value would be catA if "test_value" is in the list [1,9] else "catB". For small list I can use set of $eq inside "$or".
"category": {
"$cond": {
"if" :{
"$or" : [
{ "$eq" : ["$test_value", 1]},
{"$eq" : ["$test_value", 9] }
]
},
"then": {
"$literal" : "catA"
},
"else": {
"$literal" : "catB"
}
}
Is there any way to use something like:
"if" :{
"$in" : {"$test_value", [1,9]}
},
"then": {
"$literal" : "catA"
},
"else": {
"$literal" : "catB"
}
}
I am using mongoengine, and above syntax is not allowed.
You can do intersection of the field and the list of expected values for that field using $setIntersection and check the length of the result. If the length is bigger that 0 then the field has value from the list of expected values.
Try the following query:
db.collection.aggregate([
{
$project: {
category: {
$let: {
vars: {
resultSize: {
$size: { $setIntersection: [["$test_value"], [1, 9]] }
}
},
in: {
"$cond": {
"if": { "$gt" : ["$$resultSize", 0] },
"then": { "$literal" : "catA" },
"else": { "$literal" : "catB" }
}
}
}
}
}
}
])