简体   繁体   English

如何在Mongodb中将文档与对象属性的值匹配

[英]How to match a document with the value of an object attribute in Mongodb

I'm trying to match some document in mongoDB: 我正在尝试匹配mongoDB中的一些文档:

My Document model : 我的文档模型:

profile: {
  languages: [
    {"name": "French", "level": 1},
    {"name": "English", "level": 2},
    {"name": "Spanish", "level": 4}
  ]
}

What I (can) have to search my result set: 我(可以)要搜索的结果集:

lang = ["French", "English"];
objLang = [
  {name: "French"},
  {name: "English"}
];

What I need is to db.find() all documents that match at least one of the languages, for example : 我需要的是db.find()与至少一种语言匹配的所有文档,例如:

profile.languages.name = "French"

or 要么

profile.languages.name = "English"

WHat I mean is that if I have French or English in my option set, I need to get all the users who have a element of their languages array where name match one of my options, no matter the level of the languages. 我的意思是,如果我的选项集中有法语或英语,则无论语言级别如何,都需要让所有具有其语言数组元素名称与我的选项之一匹配的用户。

So, unless I'm wrong, I can't do 所以,除非我错了,否则我不会做

db.find({"profile.languages": {$in: [{name: "French"}, {name: "English"}]});

How would you proceed ? 您将如何进行?

Thanks a lot. 非常感谢。

David 大卫

You could try using the dot notation to access both the elements of an array and to access the fields of an embedded document: 您可以尝试使用点表示法来访问数组的两个元素并访问嵌入式文档的字段:

db.find({
    "profile.languages.name": {
        "$in": ["French", "English"]
    }
});

Actually, you were almost right: 实际上,您几乎是正确的:

db.collection.find({"profile.languages.name":{$in: ["French","English"]} })

Since profile.languages is an array of subdocuments, you can call in for one of the subdocument's keys and the subsequent query gets mapped to all subdocuments containing that key. 由于profile.languages是子文档的数组,因此您可以调用子文档的键之一,随后的查询将映射到包含该键的所有子文档。

However, without proper indexing, an added .explain() shows something pretty ugly: 但是,如果没有正确的索引.explain() ,添加的.explain()显示出一些难看的东西:

{
  "queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "test.languages",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "profile.languages.name" : {
            "$in" : [
                "English",
                "French"
            ]
        }
    },
    "winningPlan" : {
        "stage" : "COLLSCAN",
        "filter" : {
            "profile.languages.name" : {
                "$in" : [
                    "English",
                    "French"
                ]
            }
        },
        "direction" : "forward"
    },
    "rejectedPlans" : [ ]
  }
}

( serverInfo was ommited). serverInfo serverInfo)。

So in order to make this query efficient, you need to create an index over the field you want to query: 因此,为了使此查询高效,您需要在要查询的字段上创建索引:

db.languages.ensureIndex({"profile.languages.name":1})

An added explain now tells us that the matching documents are identified via the index: 现在再加上一个解释,告诉我们匹配的文档是通过索引标识的:

{
"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "test.languages",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "profile.languages.name" : {
            "$in" : [
                "English",
                "French"
            ]
        }
    },
    "winningPlan" : {
        "stage" : "FETCH",
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                "profile.languages.name" : 1
            },
            "indexName" : "profile.languages.name_1",
            "isMultiKey" : true,
            "direction" : "forward",
            "indexBounds" : {
                "profile.languages.name" : [
                    "[\"English\", \"English\"]",
                    "[\"French\", \"French\"]"
                ]
            }
        }
    },
    "rejectedPlans" : [ ]
  },
  "ok" : 1
}

Please try the below query : 请尝试以下查询:

Solution 1 : 解决方案1:

db.collection.aggregate([
     {
       $unwind:"$profile.languages"
     },
     {
       $match:{"profile.languages.name":{"$in":["French", "English"]}}
     },
     {
       $group:{_id: "$_id", profile:{"$push":"$profile.languages"}}
     }
  ])

Solution 2 : 解决方案2:

db.collection.find(
   {
     "profile.languages.name": 
       {
        "$in": [ "English", "French"]
       }
   }
 );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM