聚合计数数组成员匹配条件 [英] Aggregate Count Array Members Matching Condition
问题描述
如标题所述,我在使用MongoDB计数数组中的元素时遇到了麻烦. 我有一个只有一个文档的数据库,如下所示:
I'm having some trouble, as stated in title, to count elements in an Array using MongoDB. I have a DB with only one document, made as follow:
{_id: ObjectId("abcdefghilmnopq"),
"Array": [
{field1: "val1",
field2: "val2",
field3: "val3",
...
},
{field1: "Value1",
field2: "Value2",
field3: "Value3",
...
},
...
]
}
我想计算具有一定条件的数组元素的数量(例如field1: "a"
,并计算所有具有field1 = a
的元素).
我正在尝试使用此代码:
I wanna count the number of elements of the array which have a certain condition (e.g. field1: "a"
, and count all elements which have field1 = a
).
I'm trying with this code:
db.collection.aggregate([
{ $unwind : {path: "$Array",
includeArrayIndex: "arrayIndex"}},
{ $match : { "Array.field1" : "a"}},
{ $project : { _id : 0,
Array : 1,
arrayIndex: 1,
total: {$size: "$Array"}}}
])
但是我收到此错误:
命令失败,错误17124:'$ size的参数必须为 数组,但类型为:服务器上的对象"
Command failed with error 17124: 'The argument to $size must be an array, but was of type: object' on server
我为这个问题寻找了几种答案,但是我没有找到解决该问题的方法.我的意思是,数组"是一个数组!
i looked for several answer to this problem, but I didn't find anything resolutive for my problem. I mean, 'Array' IS an array!
预先感谢
推荐答案
错误是因为在您 $size
.
The error is because it's no longer an array after you $unwind
and therefore no longer a valid argument to $size
.
您似乎在试图合并"几个现有答案,而又不了解它们在做什么.您真正想要的是 $filter
和 $size
You appear to be attempting to "merge" a couple of existing answers without understanding what they are doing. What you really want here is $filter
and $size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
或者使用 $reduce
:
Or "reinvent the wheel" using $reduce
:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
或者您要尝试使用 $unwind
,实际上您再次 $group
以便数":有多少个匹配项:
Or for what you were trying to do with $unwind
, you actually $group
again in order to "count" how many matches there were:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
前两种形式是现代MongoDB环境的最优"形式.最终形式为 $unwind
和
The first two forms are the "optimal" for modern MongoDB environments. The final form with $unwind
and $group
is a "legacy" construct which really has not been necessary for this type of operation since MongoDB 2.6, though with some slightly different operators.
在前两个中,我们基本上是比较每个数组元素仍然是数组时的field1
值. $filter
和 $eq
运算符,它根据给定的参数是否为相等"来返回布尔值.在这种情况下,将每个数组成员的期望值设置为"a"
.
In those first two we are basically comparing the field1
value of each array element whilst it's still an array. Both $filter
and $reduce
are modern operators designed to work with an existing array in place. The same comparison is done on each one using the aggregation $eq
operator which returns a boolean value based on whether the arguments given are "equal" or not. In this case on each array member to the expected value of "a"
.
对于 $filter
,该数组实际上,除了从数组中删除不符合"cond"
中提供的条件的任何元素之外,其他元素都保持不变.由于我们仍然有一个数组"作为输出,因此我们可以使用
In the case of $filter
, the array actually remains intact except for any elements which did not meet the supplied condition in "cond"
are removed from the array. Since we still have an "array" as output we can then use the $size
operator to measure the number of array elements left after that filter condition was processed.
另一方面, $reduce
可以通过数组元素,并在每个元素上提供一个表达式以及一个存储的累加器"值,我们使用"initialValue"
对其进行了初始化.在这种情况下,相同的 $eq
测试适用于 $cond
运算符.这是一个三元"或if/then/else
条件运算符,它允许返回布尔值的已测试表达式在true
时返回then
值,在false
时返回else
值.
The $reduce
on the other hand works through the array elements and supplies an expression over each element and a stored "accumulator" value, which we initialized with "initialValue"
. In this case the same $eq
test is applied within the $cond
operator. This is a "ternary" or if/then/else
conditional operator which allows a tested expression which returns a boolean value to return the then
value when true
or the else
value when false
.
在该表达式中,我们分别返回1
或0
,并提供将返回的值和当前的累加器" "$$value"
与 $sum
运算符将它们加在一起.
In that expression we return 1
or 0
respectively and supply the overall result of adding that returned value and the current "accumulator" "$$value"
with the $sum
operator to add these together.
最终形式在数组上使用 $unwind
.这实际上是对数组成员进行解构,以便为每个数组成员及其原始文档中的相关父字段创建一个新文档".这样可以有效地复制"每个数组成员的主文档.
The final form used $unwind
on the array. What this actually does is deconstructs the array members to create a "new document" for every array member and it's related parent fields in the original document. This effectively "copies" the main document for every array member.
一旦您 $unwind
文件的结构更改为更讨人喜欢"的形式.这就是为什么您可以随后执行随后的 $match
管道的原因阶段以删除不匹配的文档.
Once you $unwind
the structure of the documents is changed to a "flatter" form. This is why you can then do the subsequent $match
pipeline stage to remove the un-matched documents.
这将我们带到 $group
将所有与公用密钥有关的信息重新组合"在一起.在这种情况下,它是原始文档的_id
字段,它当然被复制到
This brings us to $group
which is applied to "bring back together" all of the information related to a common key. In this case it's the _id
field of the original document, which was of course copied into every document produced by the $unwind
. As we go back to this "common key" as a single document, we can "count" the remaining "documents" extracted from the array using the $sum
accumulator.
如果我们想要剩下的数组",那么您可以 $push
并仅使用其余成员重建数组:
If we wanted the remaining "array" back, then you can $push
and rebuild the array with only the remaining members:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
但是,当然可以在其中使用 $size
在另一个管道阶段,我们仍然可以像使用 $sum
But of course instead of using $size
in another pipeline stage, we can simply still "count" like we already did with the $sum
这篇关于聚合计数数组成员匹配条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!