我有这样的文档结构
[{
name: "Something",
codes: [
{type: 11},
{type: 11},
{type: 15}
]
},
{
name: "Another",
codes: [
{type: 11},
{type: 12},
{type: 15},
{type: 11}
]
}]]
我需要计算集合中每个条目出现type = 11
次的次数。
我很难过。
答案 0 :(得分:5)
虽然可以应用仅$match
过滤掉包含特定类型代码的文档,但不应将其应用于此特定问题语句。因为它会从输出中过滤掉没有特定类型代码的文档。
你需要:
Unwind
每个文档都基于代码字段。project
字段wantedType
的值为1
或者值为0
。Group
在_id
字段后获取wantedType
字段的总和,其中
为您提供特定文档中所需类型代码的数量。0
为计数。代码:
var typeCountToCalculate = 11;
db.collection.aggregate([
{$unwind:"$codes"},
{$project:{"name":1,
"wantedType":{$cond:[{$eq:["$codes.type",typeCountToCalculate ]},1,0]}}},
{$group:{"_id":"$_id",
"name":{$first:"$name"},"count":{$sum:"$wantedType"}}}
])
O / P:
{
"_id" : ObjectId("54ad79dae024832588b287f4"),
"name" : "Another",
"count" : 2
}
{
"_id" : ObjectId("54ad79dae024832588b287f3"),
"name" : "Something",
"count" : 2
}
答案 1 :(得分:4)
MongoDB的聚合框架就是答案。关键操作是$unwind
,用于将数组内容处理为“规范化”文档,$group
管道阶段用于获取计数。
$match
管道阶段也在进行优化。在查询开始时,为了过滤掉在$unwind
阶段之后不可能匹配的文档,为了删除那些肯定与条件不匹配的元素(现在是文档):
db.collection.aggregate([
// Match to filter documents
{ "$match": { "codes.type": 11 }},
// Unwind to 'de-normalize'
{ "$unwind": "$codes" },
// Match to filter again, but remove the array elements
{ "$match": { "codes.type": 11 }},
// Count the occurrences of the the matches
{ "$group": {
"_id": "$codes.type",
"count": { "$sum": 1 }
}}
])
当然,如果你取出所有“匹配”,那么你会在整个系列中获得每个“类型”的“计数”。
在现代版本中,您可以使用MongoDB 2.6及更高版本的$redact
运算符稍微改变一下。如果由于这个管道阶段的递归性质而有点做作:
db.collection.aggregate([
// Match to filter documents
{ "$match": { "codes.type": 11 }},
// Filter out non matches
{ "$redact": {
"$cond": {
"if": { "$eq": [
{ "$ifNull": [ "$type", 11 ] },
11
]},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
// Unwind to 'de-normalize'
{ "$unwind": "$codes" },
// Count the occurrences of the the matches
{ "$group": {
"_id": "$codes.type",
"count": { "$sum": 1 }
}}
)
这是一种不同的过滤方式,如果您的服务器支持它,则完全有效。如果在其他示例中使用嵌套级别,请小心。
在执行任何其他操作之前,始终过滤您想要在“first”上工作的匹配值。这将从聚合管道中处理不必要的工作。如果只有10,000个可能匹配,并且这些文档中只有2,000个元素也匹配,则不得使用处理100,000个文档。
答案 2 :(得分:3)
试试这个:
db.test.aggregate([
{$unwind : "$codes"},
{$match : { 'codes.type' : 11}} ,
{$group : {
_id : { 'name': '$name', 'type' : '$codes.type'}
,count: { $sum: 1 }
}},
]).result
输出将是:
{
"0" : {
"_id" : {
"name" : "Another",
"type" : 11
},
"count" : 2
},
"1" : {
"_id" : {
"name" : "Something",
"type" : 11
},
"count" : 2
}
}