Find document with array that contains a specific

2018-12-31 15:53发布

问题:

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)

回答1:

As favouriteFoods is a simple array of strings, you can just query that field directly:

PersonModel.find({ favouriteFoods: \"sushi\" }, ...);

But I\'d also recommend making the string array explicit in your schema:

person = {
    name : String,
    favouriteFoods : [String]
}


回答2:

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\"]} }, ...);


回答3:

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/



回答4:

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 }
})


回答5:

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\"});


回答6:

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]}}}



回答7:

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} }
            ]);


回答8:

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);
}


回答9:

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.