0

I'm trying to retrieve documents where the tags array does not contain an element ignoring case sensitivity.

I'm using the inverse of my array contains query:

.find({"tags":{"$regex": "^(?!someTag$)", "$options": "i"}})

However this returns also returns documents where there's a tag that isn't "someTag".

Viktor Baert
  • 469
  • 6
  • 17

2 Answers2

0

You can get array does not include behavior with the not equal $ne operator, and case insensitivity with a collation.

Consider a collection with several tags:

> db.coll.find({},{_id:0})
{ "tags" : [ "Tag1", "Tag2", "Tag3" ] }
{ "tags" : [ "tag1", "tag2", "tag3" ] }
{ "tags" : [ "TAG4", "TAG3", "TAG5" ] }
{ "tags" : [ "tag4", "tag6", "tag7" ] }

$ne can be used to exclude exact matches:

> db.coll.find({tags:{$ne:"tag3"}},{_id:0})
{ "tags" : [ "Tag1", "Tag2", "Tag3" ] }
{ "tags" : [ "TAG4", "TAG3", "TAG5" ] }
{ "tags" : [ "tag4", "tag6", "tag7" ] }

With the addition of a collation, the $ne match can be case insensitive:

> db.coll.find({tags:{$ne:"tag3"}},{_id:0}).collation({locale:"en",strength:1})
{ "tags" : [ "tag4", "tag6", "tag7" ] }

Note that in order to use an index with this query, you will need to create an appropriate index with the same collation.

Joe
  • 19,071
  • 2
  • 15
  • 38
0

Answer provided by a colleague:

Adding a simple $not does the trick.

.find({"tags": {"$not": {"$regex": "^(?!someTag$)", "$options": "i"}}},{"tags":1})
Viktor Baert
  • 469
  • 6
  • 17