【发布时间】:2016-12-03 10:09:09
【问题描述】:
两者的功能区别是什么:
db.docs.find({ 'a.b': 'c' }, { 'a.$': 1 })
和
db.docs.find({ 'a.b': 'c' }, { 'a': { $elemMatch: { b: 'c' } } })
$elemMatch 是多余的吗?索引将如何变化?
【问题讨论】:
标签: mongodb
两者的功能区别是什么:
db.docs.find({ 'a.b': 'c' }, { 'a.$': 1 })
和
db.docs.find({ 'a.b': 'c' }, { 'a': { $elemMatch: { b: 'c' } } })
$elemMatch 是多余的吗?索引将如何变化?
【问题讨论】:
标签: mongodb
投影使用的差异有些微妙。在您的示例用法中,这些应该是等效查询(就索引使用而言),但 $elemMatch 示例不必要地重复查询条件。对于此示例,$ 投影将是更明智的选择。
文档中提到的一个本质区别是array field limitation 用于$ 投影:
由于查询文档中只能出现一个数组字段,如果该数组包含文档,要对这些文档的多个字段指定条件,请使用 $elemMatch 运算符。
关于以下投影运算符差异的一些进一步说明...
$) projection operator:将包含在查询结果中的数组字段的内容限制为包含与查询文档匹配的第一个元素。
要求匹配的数组字段包含在查询条件中
只能在查询条件中出现单个数组字段时使用
在投影中只能使用一次
$elemMatch projection operator
将包含在查询结果中的数组字段的内容限制为仅包含第一个与 $elemMatch 条件匹配的数组元素。
不要求匹配的数组在查询条件中
可用于为嵌入文档的数组元素匹配多个条件
$elemMatch query operator
请注意,还有一个 $elemMatch 查询运算符执行类似的匹配,但在查询中而不是在结果投影中。将此与 $ 投影结合使用的情况并不少见。
借用example from the docs,您可以同时使用两者:
db.students.find(
// use $elemMatch query operator to match multiple criteria in the grades array
{ grades: {
$elemMatch: {
mean: { $gt: 70 },
grade: { $gt: 90 }
}
}},
// use $ projection to get the first matching item in the "grades" array
{ "grades.$": 1 }
)
【讨论】:
如果你单独使用 $elemMatch,在查找投影中,
$elemMatch 不会过滤文档(条件不适用)
假设,'students' 包含以下文档
{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] }
{ "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] }
{ "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] }
{ "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] }
{ "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] }
{ "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }
{
"_id" : 7,
"semester" : 3,
"grades" : [
{
"grade" : 80,
"mean" : 75,
"std" : 8
},
{
"grade" : 85,
"mean" : 90,
"std" : 5
},
{
"grade" : 90,
"mean" : 85,
"std" : 3
}
]
}
{
"_id" : 8,
"semester" : 3,
"grades" : [
{
"grade" : 92,
"mean" : 88,
"std" : 8
},
{
"grade" : 78,
"mean" : 90,
"std" : 5
},
{
"grade" : 88,
"mean" : 85,
"std" : 3
}
]
}
下面的查询将返回集合中的所有文档,
db.students.find({},{ grades: { $elemMatch: { mean: 90 } } } ).pretty()
其中,下面的查询只返回匹配的记录
db.students.find({"grades.mean":90},{"grades.$":1}).pretty()
我希望索引不会对这两个查询产生任何影响
【讨论】:
$ 投影,但在某些用例中$elemMatch 更合适(例如,匹配数组元素的多个条件)。另请注意,当返回结果时,投影是在 document 级别完成的。对于您在所有文档上使用$elemMatch 的第一个示例,在您获得的结果中,您将看到_id 加上第一个匹配的grades 数组元素,或者单独看到_id(因为没有匹配的元素可以投影)。