MongoDB: operator to match arrays whose elements are all contained in a specified array

dba.stackexchange https://dba.stackexchange.com/questions/203042

  •  29-12-2020
  •  | 
  •  

Question

The $all operator selects the documents where the value of a field is an array that contains all the specified elements.

In my situation I need the opposite: an operator that selects the documents where the value of a field is an array whose elements are all contained in the specified array.

For example, consider the following collection:

{"name": 1, "vals": ["A", "B"]}
{"name": 2, "vals": ["D", "C"]}
{"name": 3, "vals": ["A", "D"]}

I want to select all the documents whose vals field contains values in ["A", "B", "D"]; that is, documents 1 and 3 (not 2 because "C" is not contained in the specified array).

I cannot use {vals: {$all: ["A", "B", "D"]}}, nor {vals: ["A", "B", "D"]} as both of these operations select the documents whose vals field contains all the specified values, which is not what I want.

Is what I need possible?

Was it helpful?

Solution

Depending on your version of MongoDB server there are a few ways to approach this.

In MongoDB 3.6+ you can use the $setIsSubset expression (which is true only when the first array given is a subset of the second) via the $expr operator:

> db.haystack.find({$expr:{$setIsSubset:["$vals",["A","B","D"]]}},{_id:0})
{
    "name": 1,
    "vals": [
        "A",
        "B"
    ]
}
{
    "name": 3,
    "vals": [
        "A",
        "D"
    ]
}

For earlier versions of MongoDB a similar outcome is possible (but less obvious) using double negation with the $elemMatch operator:

> db.haystack.find({$nor:[{vals:{$elemMatch:{$nin:["A","B","D"]}}}]},{_id:0})
{
    "name": 1,
    "vals": [
        "A",
        "B"
    ]
}
{
    "name": 3,
    "vals": [
        "A",
        "D"
    ]
}

Roughly translated: "find all documents where it is not the case that the vals array includes a value other than one in the provided list".

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top