$ projection vs $ elemMatch

时间:2014-02-03 03:19:03

标签: mongodb

之间的功能区别是什么:

db.docs.find({ 'a.b': 'c' }, { 'a.$': 1 })

db.docs.find({ 'a.b': 'c' }, { 'a': { $elemMatch: { b: 'c' } } })

$ elemMatch是多余的吗?索引将如何变化?

2 个答案:

答案 0 :(得分:10)

投影使用的差异有些微妙。在您的示例用法中,这些应该是等效查询(就索引使用而言),但$elemMatch示例不必要地重复查询条件。对于此示例,$投影将是更明智的选择。

文档中提到的一个重要差异是$预测的array field limitation

  

由于查询文档中只能出现一个数组字段,如果数组包含文档,要在这些文档的多个字段中指定条件,请使用$ elemMatch运算符。

关于以下投影算子差异的进一步说明......

positional ($) 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 }
)

答案 1 :(得分:1)

如果单独使用$ elemMatch,则在查找投影中

$ elemMatch不会过滤文件(未应用的条件)

假设'学生'包含以下文件

{ "_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()

其中as,查询下面只返回匹配的记录

db.students.find({"grades.mean":90},{"grades.$":1}).pretty()

我希望索引在任何一个查询中都没有任何区别