Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching an array field which contains any combination of the provided array in MongoDB

Tags:

mongodb

I would like to query with a specified list of array elements such that documents returned can only contain the elements I pass, but need not contain all of them.

Given documents like:

{
  name: "Article 1",
  tags: ["Funny", "Rad"]
}

{
  name: "Article 2",
  tags: ["Cool", "Rad"]
}

{
  name: "Article 3",
  tags: ["Rad"]
}

Here are some example arrays and their respective results.

  • ["Rad"] should return Article 3
  • ["Rad", "Cool"] should return Article 2 and Article 3
  • ["Funny", "Cool"] should return nothing, since there are no articles with only one of those tags or both

I'm sure I can pull this off with $where but I'd like to avoid that for obvious reasons.

like image 550
bloudermilk Avatar asked Aug 14 '14 21:08

bloudermilk


People also ask

How do you match an array field in MongoDB?

Match an Array To specify equality condition on an array, use the query document { <field>: <value> } where <value> is the exact array to match, including the order of the elements.

How do you find documents with a matching item in an embedded array?

Use $match With $eq to Find Matching Documents in an Array in MongoDB. Use $match With $all to Find Matching Documents in an Array in MongoDB.

How do I pull all elements in an array in MongoDB?

The $pullAll operator removes all instances of the specified values from an existing array. Unlike the $pull operator that removes elements by specifying a query, $pullAll removes elements that match the listed values.

How do I filter an array element in MongoDB?

Filter MongoDB Array Element Using $Filter Operator This operator uses three variables: input – This represents the array that we want to extract. cond – This represents the set of conditions that must be met. as – This optional field contains a name for the variable that represent each element of the input array.


1 Answers

You can do this by combining multiple operators:

db.test.find({tags: {$not: {$elemMatch: {$nin: ['Rad', 'Cool']}}}})

The $elemMatch with the $nin is finding the docs where a single tags element is neither 'Rad' nor 'Cool', and then the parent $not inverts the match to return all the docs where that didn't match any elements.

However, this will also return docs where tags is either missing or has no elements. To exclude those you need to add a qualifier that ensures tags has at least one element:

db.test.find({
    tags: {$not: {$elemMatch: {$nin: ['Rad', 'Cool']}}},
    'tags.0': {$exists: true}
})
like image 148
JohnnyHK Avatar answered Nov 03 '22 12:11

JohnnyHK