聚合计数数组成员匹配条件 [英] Aggregate Count Array Members Matching Condition

查看:93
本文介绍了聚合计数数组成员匹配条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如标题所述,我在使用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!

预先感谢

推荐答案

错误是因为在您

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.

在该表达式中,我们分别返回10,并提供将返回的值和当前的累加器" "$$value"

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆