如标题所述,我在使用MongoDB计算数组中的元素时遇到了一些麻烦。 我有一个只有一个文档的数据库,如下所示:
{_id: ObjectId("abcdefghilmnopq"),
"Array": [
{field1: "val1",
field2: "val2",
field3: "val3",
...
},
{field1: "Value1",
field2: "Value2",
field3: "Value3",
...
},
...
]
}
我想计算具有特定条件的数组元素的数量(例如field1: "a"
,并计算所有具有field1 = a
的元素。
我尝试使用此代码:
db.collection.aggregate([
{ $unwind : {path: "$Array",
includeArrayIndex: "arrayIndex"}},
{ $match : { "Array.field1" : "a"}},
{ $project : { _id : 0,
Array : 1,
arrayIndex: 1,
total: {$size: "$Array"}}}
])
但是我收到了这个错误:
我找了几个这个问题的答案,但我找不到解决问题的方法。我的意思是,'阵列'是一个阵列!命令失败,错误17124:' $ size的参数必须是a 数组,但类型为:object'在服务器上
提前致谢
答案 0 :(得分:1)
错误是因为它不再是$unwind
之后的数组,因此不再是$size
的有效参数。
您似乎试图“合并”一些现有答案而不了解他们正在做什么。您真正想要的是$filter
和$size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
或使用$reduce
“重新发明轮子”:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
或者您尝试使用$unwind
做什么,实际上您再次$group
以“计算”有多少匹配:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
前两种形式是现代MongoDB环境的“最佳”形式。 $unwind
和$group
的最终形式是一个“遗留”构造,自MongoDB 2.6以来,这种类型的操作实际上并不是必需的,但操作符略有不同。
在前两个中,我们基本上比较了每个数组元素的field1
值,而它仍然是一个数组。 $filter
和$reduce
都是现代运算符,旨在与现有数组配合使用。使用聚合$eq
运算符对每个运算符进行相同的比较,该运算符根据给定的参数是否“相等”返回布尔值。在这种情况下,每个数组成员的预期值为"a"
。
在$filter
的情况下,数组实际上保持不变,除了"cond"
中不符合提供条件的任何元素都从数组中删除。由于我们仍然有一个“数组”作为输出,我们可以使用$size
运算符来测量处理过滤条件后剩下的数组元素的数量。
另一方面,$reduce
通过数组元素工作,并在每个元素和存储的“累加器”值上提供表达式,我们使用"initialValue"
初始化该值。在这种情况下,$eq
运算符中会应用相同的$cond
测试。这是一个“三元”或if/then/else
条件运算符,它允许测试表达式返回一个布尔值,以便在then
时返回true
值,或在{{else
时返回false
值1}}。
在该表达式中,我们分别返回1
或0
,并提供将该返回值和当前“累加器”"$$value"
与$sum
运算符相加的总体结果将这些加在一起。
最终形式在数组上使用$unwind
。这实际上是解构数组成员为每个数组成员创建一个“新文档”,它是原始文档中的相关父字段。这有效地“复制”了每个阵列成员的主文档。
一旦$unwind
文档的结构变为“更平坦”的形式。这就是为什么然后您可以执行后续$match
管道阶段以删除未匹配的文档。
这将我们带到$group
,它被应用于“重新组合”与公共密钥相关的所有信息。在这种情况下,它是原始文档的_id
字段,当然会复制到$unwind
生成的每个文档中。当我们将这个“公共密钥”作为单个文档返回时,我们可以使用$sum
累加器“计算”从数组中提取的剩余“文档”。
如果我们想要剩下的“数组”,那么你可以$push
并仅使用其余成员重建数组:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
那样“统计”