我对这里的 $ 有一些疑问,我的数据库中有以下类型的文档:
{
"a": [
{
"p": [
{
"pid": {
"CC": "A",
"SN": "1",
"KC": "B"
}
}
]
}
]
}
当我搜索时:
这按预期工作:
db.collection.find({"a.p.pid": {"CC": "A", "SN": "1" , "KC": "B" }})
那么对于多个SN,也是这样的:
db.collection.find({ 'a.p.pid.CC': 'A', 'a.p.pid.KC': 'B', 'a.p.pid.SN': { "$in": [ "1", "2", "3" ]} })
和:
db.collection.find({"a.p.pid": {$in:[{ "CC": "A","SN": "1","KC": "B" },{ "CC": "A","SN":"2","KC": "B" } ] } } )
和:
db.collection.find({"a.p": { $elemMatch: { "pid.CC": "KR", "pid.KC": "A","pid.SN": { "$in": [ "1", "2", "3" ] } } }})
但是,我想知道,为什么这个的工作原理与第一个不同,它返回的结果是空的:
db.collection.find({"a.p.pid": { "CC": "A","KC": "B","SN": { "$in": [ "1", "2", "3" ]}}})
游乐场示例:
请指教?
我需要找到 SN 为 [“1”、“2”、“3”] 和 CC:A 和 KC:B 之一的文档
$elemMatch 是正确的选择。
所以主要问题是为什么这个迭代在 $elemmatch 中按预期工作,但在简单对象元素逗号分隔的情况下不起作用
我希望查询语言有某种正式的规范,但可惜的是,除了简单的英语文档之外,没有什么像 BNF 或任何有意义的替代方案。
$elemMatch查询的语法是:
{ <field>: { $elemMatch: { <query1>, <query2>, ... } } }
它将您的 $elemMatch 查询转换为:
<field>
:“a.p”<query1>
:{“pid.CC”:{$eq:“A”}}<query2>
: {"pid.KC": {$eq: "B"}}<query3>
: {"pid.SN": {"$in": ["1","2","3"]}}其中每个
<queryX>
被单独解析:
https://www.mongodb.com/docs/manual/reference/operator/query/eq/#syntax
{ <field>: { $eq: <value> } }
https://www.mongodb.com/docs/manual/reference/operator/query/in/#syntax
{ field: { $in: [<value1>, <value2>, ... <valueN> ] } }
现在,为什么另一个查询的行为不一样。让我用明确的
$eq
重写它,使其更明显:
{
"a.p.pid": {
$eq: {
"CC": "A",
"KC": "B",
"SN": {
"$in": [
"1",
"2",
"3"
]
}
}
}
}
传递给 $eq 运算符的整个内容是
<value>
,意味着它不会被解析为语言构造。这是数据,而不是命令。在这种情况下,与字段进行比较的值将是
{
"CC": "A",
"KC": "B",
"SN": {
"$in": [
"1",
"2",
"3"
]
}
}
作为单个 BSON。
这里最棘手的部分是在这种比较中字段的顺序很重要,这很少是理想的而且常常是意想不到的行为。在大多数情况下,您需要使用 $elemMatch 而不是整个对象比较,因为
{a:1, b:2}
与 {b:2, a:1}
不同。
事实上,并非所有工具都尊重 BSON-JSON 转换后的字段顺序,这只会让事情变得更加混乱。看看https://mongoplayground.net/p/hgsG39MEMvJ