And*_*ani 5 mongodb aggregation-framework
如标题所述,我在使用MongoDB计数数组中的元素时遇到了麻烦。我有一个只有一个文档的数据库,如下所示:
{_id: ObjectId("abcdefghilmnopq"),
"Array": [
{field1: "val1",
field2: "val2",
field3: "val3",
...
},
{field1: "Value1",
field2: "Value2",
field3: "Value3",
...
},
...
]
}
Run Code Online (Sandbox Code Playgroud)
我想计算具有一定条件的数组元素的数量(例如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"}}}
])
Run Code Online (Sandbox Code Playgroud)
但我收到此错误:
命令失败,错误17124:“ $ size的参数必须是数组,但类型为:对象”在服务器上
我为该问题寻找了几个答案,但没有找到解决该问题的方法。我的意思是,“数组”是一个数组!
提前致谢
Nei*_*unn 10
错误是因为它在你之后不再是一个数组$unwind,因此不再是$size.
您似乎试图“合并”几个现有答案,但不了解它们在做什么。你真正想要的是$filter和$size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Run Code Online (Sandbox Code Playgroud)
或“重新发明轮子”使用$reduce:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
Run Code Online (Sandbox Code Playgroud)
或者对于您尝试使用的内容$unwind,您实际上$group是为了“计算”有多少匹配项:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
Run Code Online (Sandbox Code Playgroud)
前两种形式是现代 MongoDB 环境的“最佳”形式。带有$unwindand的最终形式$group是一个“遗留”构造,自 MongoDB 2.6 以来,这种类型的操作实际上并不是必需的,尽管有一些略有不同的运算符。
在前两个中,我们基本上比较field1每个数组元素的值,而它仍然是一个数组。双方$filter并$reduce旨在与工作场所中的现有阵列现代化的运营商。使用聚合$eq运算符对每个运算符进行相同的比较,该运算符根据给定的参数是否“相等”返回一个布尔值。在这种情况下对每个数组成员的期望值"a"。
在 的情况下$filter,除了"cond"从数组中删除不满足 中提供的条件的任何元素之外,数组实际上保持完整。由于我们仍然有一个“数组”作为输出,因此我们可以使用$size运算符来测量处理过滤条件后剩余的数组元素的数量。
在$reduce通过阵列元件和建筑材料的表达式在每个元件和存储的“累加器”值,这与我们初始化另一方面作品"initialValue"。在这种情况下,同样的$eq测试适用于$cond操作员。这是一个“三元”或if/then/else条件运算符,它允许返回布尔值的测试表达式返回then值 whentrue或else值 when false。
在该表达式中,我们分别返回1or0并提供将返回值和当前“累加器”"$$value"与$sum运算符相加的总体结果,以将它们相加。
$unwind数组上使用的最终形式。这实际上是解构数组成员,为每个数组成员创建一个“新文档”,并在原始文档中与它相关的父字段。这有效地“复制”了每个数组成员的主文档。
一旦您$unwind将文档的结构更改为“更扁平”的形式。这就是为什么您可以执行后续$match管道阶段以删除不匹配的文档的原因。
这给我们带来了$group用于“将所有与公共密钥相关的信息重新组合在一起”的应用。在这种情况下,它是_id原始文档的字段,它当然被复制到$unwind. 当我们回到这个“公共密钥”作为单个文档时,我们可以“计算”使用$sum累加器从数组中提取的剩余“文档” 。
如果我们想要剩余的“数组”返回,那么您可以$push仅使用剩余成员重建数组:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Run Code Online (Sandbox Code Playgroud)
但是当然,而不是$size在另一个管道阶段使用,我们仍然可以简单地“计数”,就像我们已经对$sum