$ elemMatch在MongoDB Aggregation Framework中的$ unwind之后不起作用

时间:2013-08-05 07:21:26

标签: mongodb aggregation-framework mongo-java

我收集了以下数据:

{
  "_id" : ObjectId("51f1fcc08188d3117c6da351"),
  "cust_id" : "abc123",
  "ord_date" : ISODate("2012-10-03T18:30:00Z"),
  "status" : "A",
  "price" : 25,
  "items" : [{
      "sku" : "ggg",
      "qty" : 7,
      "price" : 2.5
    }, {
      "sku" : "ppp",
      "qty" : 5,
      "price" : 2.5
    }]
}

我正在使用查询:

cmd { "aggregate" : "orders" , "pipeline" : [ 
    { "$unwind" : "$items"} , 
    { "$match" : { "items" : { "$elemMatch" : { "qty" : { "$in" : [ 7]}}}}} , 
    { "$group" : { "price" : { "$first" : "$price"} , "items" : { "$push" : { "sku" : "$items.sku"}} , "_id" : { "items" : "$items"}}} , 
    { "$sort" : { "price" : -1}} , 
    { "$project" : { "_id" : 0 , "price" : 1 , "items" : 1}}
]}

无法理解出现了什么问题

2 个答案:

答案 0 :(得分:7)

这是因为你在$match之后正在$unwind$unwind生成新的文档流,其中items不再是数组(see docs)。

它会向每个文档发出与其中的项目一样多的次数。

如果要选择包含所需元素的文档,然后处理其所有文档,则应首先调用$match

db.orders.aggregate(
  { "$match" : { "items" : { "$elemMatch" : { "qty" : { "$in" : [ 7]}}}}},
  { "$unwind" : "$items"},
  ...
);

如果您想在$unwind之后选择要处理的项目,则应删除$elemMatch

db.orders.aggregate(
  { "$unwind" : "$items"},
  { "$match" : { "items.qty" : { "$in" : [7]}}},
  ...
);

在第一种情况下,您将获得两份文件:

{ 
  "price" : 25,
  "items" : [
    {"sku" : "ppp"}
  ]
},
{
  "price" : 25,
  "items" : [
    {"sku" : "ggg"}
  ]
}

在第二种情况下你会得到一个:

{
  "price" : 25,
  "items" : [
    {"sku" : "ggg"}
  ]
}

<强>更新即可。在$unwind后,您的文档将如下所示:

{
  "_id" : ObjectId("51f1fcc08188d3117c6da351"),
  "cust_id" : "abc123",
  "ord_date" : ISODate("2012-10-03T18:30:00Z"),
  "status" : "A",
  "price" : 25,
  "items" : {
    "sku" : "ggg",
    "qty" : 7,
    "price" : 2.5
  }
}

答案 1 :(得分:2)

对于少量文件,放松和匹配很好。但是大量的文件,最好做 - 匹配($ elemMatch),放松,再次匹配。

db.orders.aggregate(
  { "$match" : { "items" : { "$elemMatch" : { "qty" : { "$in" : [ 7]}}}}},
  { "$unwind" : "$items"},
  { "$match" : { "items.qty" : { "$in" : [7]}}}
  ...
  ...
);

第一场比赛将仅过滤与qty标准匹配的文档。在所选文档中,第二个匹配将删除与qty标准不匹配的子文档。