查找包含特定值的数组的文档


499

如果我有这个架构...

person = {
    name : String,
    favoriteFoods : Array
}

...在其中favoriteFoods用字符串填充数组。我怎么能找到所有以猫鼬为食的人?

我一直希望以下方面的东西:

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

(我知道$containsmongodb中没有此功能,只是在知道解决方案之前先解释了我期望找到的内容)

Answers:


693

正如favouriteFoods一个简单的字符串数组一样,您可以直接查询该字段:

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

但我也建议您在架构中使字符串数组显式显示:

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

相关文档可以在这里找到:https : //docs.mongodb.com/manual/tutorial/query-arrays/


19
如果满足以下条件,favouriteFoods则此方法也适用:favouriteFoods:[{type:Schema.Types.ObjectId, ref:'Food'}]
k88074 2014年

12
作为来自像MySQL之类的RDBMS的Mongo新手,发现这样的解决方案是如此简单,不需要JOIN和附加表,这让我感到奇怪,为什么我不早就开始使用Mongo。但这并不是说任何一个DBMS都优于另一个DBMS-这取决于您的用例。
Irvin Lim 2015年

9
不要误会。即使这是字典列表,您仍然可以通过这种方式查询它。范例: PersonModel.find({ favouriteFoods.text: "sushi" }, ...); person = { name : String, favouriteFoods : [{text:String}] }
Aminah Nuraini 2015年

3
当我想找到一个包含至少两个字符串的数组时会发生什么?
王王航空

151

$containsmongodb中没有运算符。

您可以使用JohnnyHK的答案,因为它可以起作用。包含mongo的最接近的类比是$in,使用此查询,您的查询将类似于:

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

10
它是否正确?mongodb使用$ in时不期望值数组吗?例如{name:{$ in:[“ Paul”,“ Dave”,“ Larry”,“ Adam”]}}?
路德维希·马格努森

37
??这是不必要的。$in当您有多个查询值并且文档需要匹配其中一个时,使用。相反(这就是这个问题的意思),JohnnyHK的答案是正确的。我本来打算投票,但我想这个答案可能对其他最终访问此页面的人有所帮助。
MalcolmOcean 2015年

4
但这帮助我实际查询了几个值:D非常感谢!
亚历山大·布尔里尔

10
谢谢。这是我实际上正在寻找的搜索多个值的方法:PersonModel.find({favouriteFoods: {"$in": ["sushi", "hotdog"]}})
totymedli

@MalcolmOcean是正确的,因为$ in运算符是反向的,具有一个数组作为value。问题是关于数组的字段。然而,如果这两个字段和值是数组,那么这两个这样的回答和JohnnyHK的是相关的,这意味着你需要$。
tscizzle's

87

我觉得$all在这种情况下会更合适。如果您正在寻找喜欢寿司的人,可以这样做:

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

您可能希望过滤更多搜索内容,例如:

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

$in就像OR或$allAND。检查一下:https : //docs.mongodb.com/manual/reference/operator/query/all/


抱歉,这是我问题的不正确答案。我不是在寻找精确匹配,而是在寻找至少包含指定值的数组。
路德维希·马格努森

17
这是对您问题的完美答案!对于一个值,使用$ all或$ in没有区别。如果您具有“ sushi”,“ bananas”之类的多个值,则$ all会在其最喜欢的食物数组中查找具有“ sushi”和“ bananas”的人,如果使用$ in,则将获得具有“ sushi”或“ bananas”的人在他们最喜欢的食物系列中。
Jodo

是的,没有$包含,但是$ all
差不多-daddinhquoc

2
最好的答案。
Nikolay Tsenkov,

65

如果数组包含对象,例如if favouriteFoods是以下对象的数组:

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

您可以使用以下查询:

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

2
这很容易是最好的答案。赶时间使用起来容易得多。
Uber Schnoz

这应该是选定的答案。如果要在MongoDB中查询嵌套文档的数组,这就是您的方法。不知道这是否是最有效的,但是如果您只是想这样做,那么这就是您所需要的。
Kyle L.

32

如果需要在子文档数组中查找包含NULL元素的文档,我发现此查询的效果很好:

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

该查询摘自该帖子:具有空值的MongoDb查询数组

这是一个很好的发现,它比我自己的初始版本和错误版本要好得多(原来的版本只适用于具有一个元素的数组):

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

3

尽管同意find()在您的用例中最有效。仍然存在$ match聚合框架,以简化对大量条目的查询,并生成少量对您有价值的结果,尤其是在分组和创建新文件时。

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

不适用于mongodb 4.2 ..请回复
vimmi

您遇到什么错误,请提供详细信息?
阿米特什

3

如果lookup_food_array是数组。

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

如果lookup_food_array是字符串。

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

1

对于Loopback3,给出的所有示例都不适用于我,或者说与使用REST API一样快。但这帮助我弄清楚我需要的确切答案。

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


1
您是救生员,谢谢!那是哪里记录在案的,我错过了?你能发布链接吗?谢谢。
user2078023

-3

如果您想通过javascript使用类似“包含”运算符的内容,则可以始终使用正则表达式...

例如。假设您要检索以“ Bartolomew”作为名称的客户

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

-26

我知道这个话题很老,但是对于将来可能会想知道相同问题的人们,另一种效率极低的解决方案是:

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

这避免了MongoDB的所有优化,因此请勿在生产代码中使用。


出于好奇,这样做有什么好处吗?
路德维希·马格努森

5
与公认的答案相比,这是非常低效的;它规避了Mongo在幕后进行的所有优化,以便像公认的那样直接查找。

1
不过,这正是我需要的答案!谢谢“用户” :)
Vasyl Boroviak
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.