A colleague asked me how to find documents where the array of objects called "trans" has the following properties: one element contains a:0 and it's immediately followed by an element where a:1 and s>3.
In other words, flag the document that has trans array with element { ..., a:0, ...} immediately followed by element with { ..., a:1, s: N, ... } where N is greater than 3 or one that looks like this:
{
...
"trans" : [..., {...}, {..., a:0, ...}, {.., a:1, s:4, ...}, {...}, ...],
...
}
Here's the aggregation stage that adds a true or false field that indicates whether such a pattern was found in the "trans" array:
In other words, flag the document that has trans array with element { ..., a:0, ...} immediately followed by element with { ..., a:1, s: N, ... } where N is greater than 3 or one that looks like this:
{
...
"trans" : [..., {...}, {..., a:0, ...}, {.., a:1, s:4, ...}, {...}, ...],
...
}
Here's the aggregation stage that adds a true or false field that indicates whether such a pattern was found in the "trans" array:
{$addFields: {bad: {$in:[true, {$map:{ input: {$range:[0,{$subtract:[{$size:"$trans"},1]} ]}, as: "z", in: {$let: { vars: { e: {$arrayElemAt:["$trans","$$z"]}, e1: {$arrayElemAt:["$trans",{$add:[1,"$$z"]}]} }, in: {$cond: { if: {$and:[ {$eq:["$$e.a",0] },{$eq:["$$e1.a",1]}, {$gt:["$$e1.s",3]} ]}, then: true, else: false } } }} }} ]} } }
To elaborate: using "$range" we generate "z", an array of integers we'll $map to traverse "trans" and then we create two variables with "$let" which represent the array element at position "z" and at position "z+1". We then check our conditions and if all of them are true, we output "true" otherwise "false". The resultant array of booleans is checked using "$in" expression to see if "true" appears anywhere in it.
This stage uses several 3.4 features, the "$addFields" stage, as well as the $range and $in expressions. We could have used "$anyElementTrue" expression instead of "$in" and "$project" instead of "$addFields" (though then we would need to know all the fields we wanted to pass through) but there is no equivalent to "$range" before 3.4, so without it, we would need to do far more complex manipulation involving "$unwind" with "includeArrayIndex" option (which was introduced in 3.2) followed by "$group". If at all possible, just upgrade to 3.4 if you need to do intra-array comparisons.
This stage uses several 3.4 features, the "$addFields" stage, as well as the $range and $in expressions. We could have used "$anyElementTrue" expression instead of "$in" and "$project" instead of "$addFields" (though then we would need to know all the fields we wanted to pass through) but there is no equivalent to "$range" before 3.4, so without it, we would need to do far more complex manipulation involving "$unwind" with "includeArrayIndex" option (which was introduced in 3.2) followed by "$group". If at all possible, just upgrade to 3.4 if you need to do intra-array comparisons.