[mongodb] Find document with array that contains a specific value

If I have this schema...

person = {
    name : String,
    favoriteFoods : Array
}

... where the favoriteFoods array is populated with strings. How can I find all persons that have "sushi" as their favorite food using mongoose?

I was hoping for something along the lines of:

PersonModel.find({ favoriteFoods : { $contains : "sushi" }, function(...) {...});

(I know that there is no $contains in mongodb, just explaining what I was expecting to find before knowing the solution)

This question is related to mongodb mongoose

The answer is


I feel like $all would be more appropriate in this situation. If you are looking for person that is into sushi you do :

PersonModel.find({ favoriteFood : { $all : ["sushi"] }, ...})

As you might want to filter more your search, like so :

PersonModel.find({ favoriteFood : { $all : ["sushi", "bananas"] }, ...})

$in is like OR and $all like AND. Check this : https://docs.mongodb.com/manual/reference/operator/query/all/


In case that the array contains objects for example if favouriteFoods is an array of objects of the following:

{
  name: 'Sushi',
  type: 'Japanese'
}

you can use the following query:

PersonModel.find({"favouriteFoods.name": "Sushi"});

In case you need to find documents which contain NULL elements inside an array of sub-documents, I've found this query which works pretty well:

db.collection.find({"keyWithArray":{$elemMatch:{"$in":[null], "$exists":true}}})

This query is taken from this post: MongoDb query array with null values

It was a great find and it works much better than my own initial and wrong version (which turned out to work fine only for arrays with one element):

.find({
    'MyArrayOfSubDocuments': { $not: { $size: 0 } },
    'MyArrayOfSubDocuments._id': { $exists: false }
})

For Loopback3 all the examples given did not work for me, or as fast as using REST API anyway. But it helped me to figure out the exact answer I needed.

{"where":{"arrayAttribute":{ "all" :[String]}}}


I know this topic is old, but for future people who could wonder the same question, another incredibly inefficient solution could be to do:

PersonModel.find({$where : 'this.favouriteFoods.indexOf("sushi") != -1'});

This avoids all optimisations by MongoDB so do not use in production code.


Though agree with find() is most effective in your usecase. Still there is $match of aggregation framework, to ease the query of a big number of entries and generate a low number of results that hold value to you especially for grouping and creating new files.

  PersonModel.aggregate([
            { 
                 "$match": { 
                     $and : [{ 'favouriteFoods' : { $exists: true, $in: [ 'sushi']}}, ........ ]  }
             },
             { $project : {"_id": 0, "name" : 1} }
            ]);

Incase of lookup_food_array is array.

match_stage["favoriteFoods"] = {'$elemMatch': {'$in': lookup_food_array}}

Incase of lookup_food_array is string.

match_stage["favoriteFoods"] = {'$elemMatch': lookup_food_string}

There is no $contains operator in mongodb.

You can use the answer from JohnnyHK as that works. The closest analogy to contains that mongo has is $in, using this your query would look like:

PersonModel.find({ favouriteFoods: { "$in" : ["sushi"]} }, ...);

If you'd want to use something like a "contains" operator through javascript, you can always use a Regular expression for that...

eg. Say you want to retrieve a customer having "Bartolomew" as name

async function getBartolomew() {
    const custStartWith_Bart = await Customers.find({name: /^Bart/ }); // Starts with Bart
    const custEndWith_lomew = await Customers.find({name: /lomew$/ }); // Ends with lomew
    const custContains_rtol = await Customers.find({name: /.*rtol.*/ }); // Contains rtol

    console.log(custStartWith_Bart);
    console.log(custEndWith_lomew);
    console.log(custContains_rtol);
}