Mongodb聚合显示计数在多个字段上为零值

时间:2016-11-28 04:18:27

标签: mongodb mongodb-query aggregation-framework

我尝试在多个字段上应用聚合来显示计数,但它不起作用。

我有4到5个不同的值让我们说value1,value2,value3,value4,value5但是这不是固定的,它可能是重复值。我希望显示该值与相对计数,如我的输出,它还应显示field2值和计数与结果输出。

这是我的查询

db.Collection.aggregate([
  { $group: {
     {
       "_id": {field1:"$field1",field2:"$field2"}
    }
  },
  { 
    "count": { "$sum": 1 }
  }
]);

这是我的数据

    { 
    "_id" : "1",
    "field1" : "value1", 
    "field2" : "abc"
}
{ 
    "_id" : "2",
    "field1" : "value2", 
    "field2" : "xyz"
}
{ 
    "_id" : "3",
    "field1" : "value2", 
    "field2" : "abc"
}
{ 
    "_id" : "4",
    "field1" : "value3", 
    "field2" : "abc"
}
{ 
    "_id" : "5",
    "field1" : "value1", 
    "field2" : "xyz"
}
{ 
    "_id" : "6",
    "field1" : "value3", 
    "field2" : "xyz"
}
{ 
    "_id" : "7",
    "field1" : "value1", 
    "field2" : "abc"
}
{ 
    "_id" : "8",
    "field1" : "value2", 
    "field2" : "xyz"
}
{ 
    "_id" : "9",
    "field1" : "value1", 
    "field2" : "abc"
}
{ 
    "_id" : "10",
    "field1" : "value1", 
    "field2" : "abc"
}
{ 
    "_id" : "11",
    "field1" : "value2", 
    "field2" : "xyz"
}

,我的输出假设是这样的:

{ 
 "field1.value1" : 0
}
{ 
"field1.value2" : 1
}
{ 
"field1.value3" : 12
}
{
 "field2.abc" : 50
}
{
 "field2.xyz" : 5
}

让我知道它是如何可能的。

2 个答案:

答案 0 :(得分:0)

$ group阶段允许您在多个字段上拥有_id。这会为您不同字段的所有现有组合创建分组。

首先,计数字段和累加器'总和'应该在小组赛阶段。

db.collection.aggregate([
  { $group: {
     {
       "_id": { field1:"$field1", field2:"$field2" },
       "count": { "$sum": 1 }
    }
  }
]);

然后,您可以通过减少数量的条目在客户端汇总结果。由于' field1'的唯一值的数量,这将花费可忽略的时间量。和' field2'与原始文件组相比,它会非常少。

我能想到的另一个选择是使用多个聚合查询,但这完全取决于你的性能。

答案 1 :(得分:0)

您可以使用3.4中的$objectToArray运算符执行此操作。

db.foo.aggregate([
  {$project: {x: {$objectToArray: "$$CURRENT"}}}
  ,{$unwind: "$x"}
  ,{$match: {"x.k": {$ne: "_id"}}}
  ,{$group: {_id: {f:"$x.k", v: "$x.v"}, n: {$sum:1}}}
  ,{$project: {fv: {$concat: [ "$_id.f", ".", "$_id.v" ]}, n:1, _id:0 }}
                    ]);

这可以在任意数量的字段上动态运行。如果您想限制它正在做的事情,请添加{$match: {"$x.k": {$ne: "fieldname you don't want"}}} 这是上面发布的输入的输出:

{ "n" : 5, "fv" : "field2.xyz" }
{ "n" : 4, "fv" : "field1.value2" }
{ "n" : 2, "fv" : "field1.value3" }
{ "n" : 6, "fv" : "field2.abc" }
{ "n" : 5, "fv" : "field1.value1" }

这是一个符合确切规范的解决方案,使用$arrayToObject“重新合成”具有所需字段名称的文档:

db.foo.aggregate([
  {$project: {x: {$objectToArray: "$$CURRENT"}}}
  ,{$unwind: "$x"}
  ,{$match: {"x.k": {$ne: "_id"}}}
  ,{$group: {_id: {f:"$x.k", v: "$x.v"}, n: {$sum:1}}}
  ,{$project: { _id:0, xx: [ [ {$concat: ["$_id.f", ".", "$_id.v"]}, "$n"] ] }}
  ,{$replaceRoot: { newRoot: {$arrayToObject: "$xx"}}}
                    ]);

产量:

{ "field2.xyz" : 5 }
{ "field1.value2" : 4 }
{ "field1.value3" : 2 }
{ "field2.abc" : 6 }
{ "field1.value1" : 5 }