Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find documents with array that doesn't contains a specific value

I have the following model:

var PersonSchema = new Schema({     name: String,     groups: [         {type: Schema.Types.ObjectId, ref: 'Group'}     ], }); 

I am looking for a query that retrieves all the Persons that are not part of a certain Group (i.e the persons' group array doesn't contain the id of the specified group).

I was thinking about something like this, but I'm not sure it is correct:

Person.find({groups: {$nin: [group._id]})

like image 542
Marius Avatar asked Oct 21 '14 07:10

Marius


People also ask

How do you check if an array contains a specific value?

JavaScript Array includes() The includes() method returns true if an array contains a specified value. The includes() method returns false if the value is not found.

How to use nin in MongoDB?

MongoDB provides different types of comparison query operators and $nin (not in) operator is one of them. This operator is used to select those documents where the value of the field is not equal to any of the given value in the array and the field that does not exist.

What is MongoDB elemMatch?

The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.


2 Answers

Nothing wrong with what you are basically attempting, but perhaps the only clarification here is the common misconception that you need operators like $nin or $in when querying an array.

Also you really need to do here is a basic inequality match with $ne:

Person.find({ "groups": { "$ne": group._id } }) 

The "array" operators are not for "array targets" but for providing a "list" of conditions to test in a convenient form.

Person.find({ "groups": { "$nin": [oneId, twoId,threeId] } }) 

So just use normal operators for single conditions, and save $in and $nin for where you want to test more than one condition against either a single value or a list. So it's just the other way around.

If you do need to pass a "list" of arguments where "none" of those in the provided list match the contents of the array then you reverse the logic with the $not operator and the $all operator:

Person.find({ "groups": { "$not": { "$all": [oneId,twoId,threeId] } } }) 

So that means that "none of the list" provided are present in the array.

like image 178
Neil Lunn Avatar answered Sep 23 '22 09:09

Neil Lunn


This is a better way to do this in Mongoose v5.11:

Person.find({ occupation: /host/ }).where('groups').nin(['group1', 'group2']); 

The code becomes clearer and has more readability.

like image 28
matymad Avatar answered Sep 22 '22 09:09

matymad