MongoDB Aggregation - match if value in array

eml002 picture eml002 · May 29, 2015 · Viewed 45.2k times · Source

I have a collection that I'm performing an aggregation on and I've basically gotten it down to

{array:[1,2,3], value: 1},
{array:[1,2,3], value: 4}

How would I perform an aggregation match to check if the value is in the array? I tried using {$match: {"array: {$in: ["$value"]}}} but it doesn't find anything.

I would want the output (if using the above as an example) to be:

{array:[1,2,3], value:1}

Answer

Blakes Seven picture Blakes Seven · Jul 5, 2015

As stated, $where is a good option where you do not need to continue the logic in the aggregation pipeline.

But if you do then use $redact, with $map to transform the "value" into an array and use of $setIsSubSet to compare. It is the fastest way to do this since you do not need to duplicate documents using $unwind:

db.collection.aggregate([
   { "$redact": {
       "$cond": {
           "if": { "$setIsSubset": [
                { "$map": {
                    "input": { "$literal": ["A"] },
                    "as": "a",
                    "in": "$value"
                }},
                "$array"
           ]},
           "then": "$$KEEP",
           "else": "$$PRUNE"
       }
   }}
])

The $redact pipeline operator allows the proccessing of a logical condition within $cond and uses the special operations $$KEEP to "keep" the document where the logical condition is true or $$PRUNE to "remove" the document where the condition was false.

This allows it to work like $project with a subsequent $match, but in a single pipeline stage which is more efficient.

Considering these are native coded operators and not JavaScript then it is likely "the" fastest way to perform your match. So provided you are using a MongoDB 2.6 version or above, then this is the way you should be doing it to compare these elements in your document.