【问题标题】:Find document with array that contains a specific value查找包含特定值的数组的文档
【发布时间】:2020-04-19 19:03:54
【问题描述】:

如果我有这个架构...

person = {
    name : String,
    favoriteFoods : Array
}

...favoriteFoods 数组填充了字符串。如何使用猫鼬找到所有将“寿司”作为他们最喜欢的食物的人?

我希望得到类似的东西:

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

(我知道mongodb中没有$contains,只是解释一下我在知道解决方案之前期望找到的东西)

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    由于favouriteFoods 是一个简单的字符串数组,您可以直接查询该字段:

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

    但我也建议在您的架构中明确地显示字符串数组:

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

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

    【讨论】:

    • 这也适用于favouriteFoods 是:favouriteFoods:[{type:Schema.Types.ObjectId, ref:'Food'}]
    • 作为一个刚从 MySQL 这样的 RDBMS 开始接触 Mongo 的人,发现这样的解决方案不需要 JOIN 和额外的表就可以这么简单地工作,这让我想知道为什么我没有早点开始使用 Mongo。但这并不是说任何一个 DBMS 都优于另一个 - 这取决于您的用例。
    • 别搞错了。即使是dict列表,你仍然可以这样查询。示例:PersonModel.find({ favouriteFoods.text: "sushi" }, ...); person = { name : String, favouriteFoods : [{text:String}] }
    • 当我想找到一个至少包含两个字符串的数组时会发生什么?
    • @AeroWang 使用这个db.person.find( { favouriteFoods: { $all: ["sushi", "sashimi"] } } ) 将返回所有喜欢“寿司”和“生鱼片”的人,有人在下面指出了一些答案
    【解决方案2】:

    mongodb 中没有$contains 运算符。

    您可以使用 JohnnyHK 的答案。与包含 mongo 的最接近的类比是 $in,使用它您的查询将如下所示:

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

    【讨论】:

    • 这是正确的吗?使用 $in 时,mongodb 不期望值数组吗?比如 { name : { $in : [ "Paul", "Dave", "Larry" , "Adam"] }}?
    • 嗯?这是不必要的。 $in 用于当您有多个查询值并且文档需要匹配其中一个时。相反(这就是这个问题的目的),JohnnyHK 的回答是正确的。我打算投反对票,但我想这个答案可能对最终访问此页面的其他人有所帮助。
    • 但这帮助我实际查询了几个值 :D 非常感谢!
    • 谢谢。这就是我真正想要的,搜索多个值的方法:PersonModel.find({favouriteFoods: {"$in": ["sushi", "hotdog"]}})
    • @MalcolmOcean 是正确的,因为 $in 运算符是相反的,将数组作为 field 是一个数组,这就是问题所在。但是,如果 both 字段和值都是数组,那么这个答案和 JohnnyHK 都是相关的,这意味着你确实需要 $in。
    【解决方案3】:

    我知道这个话题已经过时了,但是对于可能想知道同样问题的未来人来说,另一个非常低效的解决方案可能是:

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

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

    【讨论】:

    • 出于好奇,这样做有什么好处吗?
    • 与公认的答案相比,这非常低效;它规避了 Mongo 在幕后进行的所有优化,以便在接受时直接找到。
    • 这正是我需要的答案!谢谢“用户”:)
    【解决方案4】:

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

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

    此查询摘自此帖子:MongoDb query array with null values

    这是一个很棒的发现,它比我自己最初的 和错误 版本好得多(结果证明它只适用于具有一个元素的数组):

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

    【讨论】:

      【解决方案5】:

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

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

      您可能希望过滤更多搜索,如下所示:

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

      $in 类似于 OR,$all 类似于 AND。检查这个:https://docs.mongodb.com/manual/reference/operator/query/all/

      【讨论】:

      • 抱歉,我的问题的答案不正确。我不是在寻找精确匹配,而只是寻找至少包含指定值的数组。
      • 这是对您问题的完全有效答案!对于一个值,使用 $all 或 $in 没有区别。如果您有多个值,例如“sushi”、“bananas”,$all 正在寻找在他们最喜爱的Food 数组中有“sushi”和“bananas”的人,如果使用 $in,您会得到有“sushi”或“bananas”的人“在他们最喜欢的食物阵列中。
      • 是的,没有 $contains 但 $all 是这样的
      【解决方案6】:

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

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

      您可以使用以下查询:

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

      【讨论】:

      • 这无疑是最好的答案。赶时间时更容易使用。
      • 这应该是选择的答案。如果您正在处理查询 MongoDB 中的嵌套文档数组,这就是您的操作方式。不确定它是否是最有效的,但如果这就是你想要做的,这就是你所需要的。
      【解决方案7】:

      对于 Loopback3,给出的所有示例都不适用于我,或者无论如何都不像使用 REST API 一样快。但它帮助我找出了我需要的确切答案。

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

      【讨论】:

      • 你是救生员,谢谢!那是在哪里记录的,我错过了?请问可以发链接吗?谢谢。
      【解决方案8】:

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

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

      【讨论】:

      • 您遇到什么错误,请详细说明?
      【解决方案9】:

      如果您想通过 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);
      }
      

      【讨论】:

        【解决方案10】:

        lookup_food_array 的情况是数组。

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

        lookup_food_array 的情况是字符串。

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

        【讨论】:

          【解决方案11】:

          有一些方法可以实现这一点。第一个是$elemMatch操作员:

          const docs = await Documents.find({category: { $elemMatch: {$eq: 'yourCategory'} }});
          // you may need to convert 'yourCategory' to ObjectId
          

          第二个是$in$all 运营商:

          const docs = await Documents.find({category: { $in: [yourCategory] }});
          

          const docs = await Documents.find({category: { $all: [yourCategory] }});
          // you can give more categories with these two approaches 
          //and again you may need to convert yourCategory to ObjectId
          

          $in 类似于 OR,$all 类似于 AND。欲了解更多详情,请查看此链接:https://docs.mongodb.com/manual/reference/operator/query/all/

          第三个是aggregate()函数:

          const docs = await Documents.aggregate([
              { $unwind: '$category' },
              { $match: { 'category': mongoose.Types.ObjectId(yourCategory) } }
          ]};
          

          使用 aggregate() 您只能在类别数组中获得一个类别 ID。

          我从我的项目中获得此代码 sn-ps,我必须在其中找到具有特定类别/类别的文档,因此您可以根据需要轻松自定义它。

          【讨论】:

            【解决方案12】:

            使用 populate$in,此代码将很有用。

            ServiceCategory.find().populate({
                path: "services",
                match: { zipCodes: {$in: "10400"}},
                populate: [
                    {
                        path: "offers",
                    },
                ],
            });
            

            【讨论】:

              猜你喜欢
              • 2014-12-16
              • 2016-12-11
              • 2017-07-08
              • 2017-05-01
              • 2019-01-27
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多