MongoDB(3.0)聚合:多个匹配与一个匹配多个项目

时间:2015-05-27 07:06:06

标签: mongodb mongodb-query

我正在开发一个项目,要求我根据很多匹配(可能是100)来动态创建动态MongoDB查询。除了创建正确的索引之外,我想知道我是如何将匹配构建到管道中的。基于以下示例,这些示例中的一个是否与另一个示例的表现不同或更好?

我假设示例2会缩小结果集,但会更多调用?也许这就是示例1在幕后做的事情?

提前感谢您的帮助!

示例1

db.Test.aggregate(
[     
   { $match: { item1: 'foo1', item2: 'foo2', item3: 'foo3' } }
])

VS

示例2

db.Test.aggregate(
[     
   { $match: { item1: 'foo1' } },
   { $match: { item2: 'foo2' } },
   { $match: { item3: 'foo3' } }
])

我怀疑这个问题是否重要,但如果相关,我将使用C#驱动程序进行实施。

2 个答案:

答案 0 :(得分:4)

我在MongoDB's documentation中找到了以下信息:

  

$match + $match合并

     

$match紧跟另一个$match后,这两个阶段可以合并为一个$ match,将条件与$and组合在一起。例如,管道包含以下序列:

{ $match: { year: 2014 } },
{ $match: { status: "A" } }
     

然后第二个$ match阶段可以合并到第一个$ match阶段并产生一个$ match阶段:

{ $match: { $and: [ { "year" : 2014 }, { "status" : "A" } ] } }

由此可以说,在raw中使用多个$match与使用包含多个字段的单个$match完全相同。

我不确定为什么优化引擎会在这里添加$and运算符。根据{{​​3}},它没有必要,因此我认为可以忽略它。有人可以证实吗?

答案 1 :(得分:1)

我今天想知道同样的事情,偶然发现了罗曼的回答。虽然我想亲眼看到这个,但可以使用两个聚合的解释轻松完成;

db.verpakking.explain().aggregate([
    { "$match": {type: "VERPAKT"} },
    { "$match": {ras: "CherryStar"} },
]);

这导致以下输出:

{
  "waitedMS" : NumberLong(0),
  "stages" : [
    {
      "$cursor" : {
        "query" : {
          "$and" : [
            {
              "type" : "VERPAKT"
            },
            {
              "ras" : "CherryStar"
            }
          ]
        },
        "queryPlanner" : {
          "plannerVersion" : NumberInt(1),
          "namespace" : "denberk.verpakking",
          "indexFilterSet" : false,
          "parsedQuery" : {
            "$and" : [
              {
                "ras" : {
                  "$eq" : "CherryStar"
                }
              },
              {
                "type" : {
                  "$eq" : "VERPAKT"
                }
              }
            ]
          },
          "winningPlan" : {
            "stage" : "COLLSCAN",
            "filter" : {
              "$and" : [
                {
                  "ras" : {
                    "$eq" : "CherryStar"
                  }
                },
                {
                  "type" : {
                    "$eq" : "VERPAKT"
                  }
                }
              ]
            },
            "direction" : "forward"
          },
          "rejectedPlans" : [

          ]
        }
      }
    }
  ],
  "ok" : NumberInt(1)
}

虽然

db.verpakking.explain().aggregate([
{ "$match": {type: "VERPAKT", ras: "CherryStar"} },
]);

输出结果:

{
  "waitedMS" : NumberLong(0),
  "stages" : [
    {
      "$cursor" : {
        "query" : {
          "type" : "VERPAKT",
          "ras" : "CherryStar"
        },
        "queryPlanner" : {
          "plannerVersion" : NumberInt(1),
          "namespace" : "denberk.verpakking",
          "indexFilterSet" : false,
          "parsedQuery" : {
            "$and" : [
              {
                "ras" : {
                  "$eq" : "CherryStar"
                }
              },
              {
                "type" : {
                  "$eq" : "VERPAKT"
                }
              }
            ]
          },
          "winningPlan" : {
            "stage" : "COLLSCAN",
            "filter" : {
              "$and" : [
                {
                  "ras" : {
                    "$eq" : "CherryStar"
                  }
                },
                {
                  "type" : {
                    "$eq" : "VERPAKT"
                  }
                }
              ]
            },
            "direction" : "forward"
          },
          "rejectedPlans" : [

          ]
        }
      }
    }
  ],
  "ok" : NumberInt(1)
}

正如您所看到的,这与“查询”部分完全相同(这是正常的,因为我们的查询 不同)。这证明无论您使用两个单独的连续$ match-pipelines还是一个组合$ match-pipeline,解析后的查询都将完全相同。