【问题标题】:MongoDB aggregate count based on multiple query fields - (Multiple field count)MongoDB 基于多个查询字段的聚合计数 - (Multiple field count)
【发布时间】:2015-11-09 00:57:38
【问题描述】:

我的收藏会这样,

{
    "_id" : ObjectId("55c8bd1d85b83e06dc54c0eb"),
    "name" : "xxx",
    "salary" : 10000,
    "type" : "type1"
}
{
    "_id" : ObjectId("55c8bd1d85b83e06dc54c0eb"),
    "name" : "aaa",
    "salary" : 10000,
    "type" : "type2"
}
{
    "_id" : ObjectId("55c8bd1d85b83e06dc54c0eb"),
    "name" : "ccc",
    "salary" : 10000,
    "type" : "type2"
}

我的查询参数将作为,

{salary=10000, type=type2}

所以根据查询我需要获取上述查询参数的计数

结果应该是这样的,

{ 类别:'type1',计数:500 } { 类别:'type2',计数:200 } {类别:'name',计数:100 }

现在我通过点击三个不同的查询并构造结果(或)服务器端迭代来获得计数,我可以获得结果。

谁能建议或提供我获得上述结果的好方法

【问题讨论】:

  • 你最好展示一下你目前在做什么。您的解释目前尚不清楚,因为您的“参数”与您想要的输出之间的关系。
  • @Blakes,我的条件将是或条件(例如薪水>10000,名称=xxx)在此条件中我需要获取通过此条件的薪水计数和姓名计数谁有过相同的。

标签: mongodb mapreduce mongodb-query aggregation-framework


【解决方案1】:

您的问题没有很清楚地提出,但您似乎想要在这里做的是计算字段中数据的出现次数,可选择通过匹配条件的值过滤这些字段。

这里$cond 运算符允许您将logical condition 转换为值:

db.collection.aggregate([
    { "$group": {
        "_id": null,
        "name": { "$sum": 1 },
        "salary": { 
            "$sum": { 
                "$cond": [
                    { "$gte": [ "$salary", 1000 ] },
                    1,
                    0
                ]
            }
        },
        "type": { 
            "$sum": { 
                "$cond": [
                    { "$eq": [ "$type", "type2" ] },
                    1,
                    0
                ]
            }
        }
    }}
])

所有值都在同一个文档中,在这里将它们分开没有任何意义,因为这是管道中的额外工作。

{ "_id" : null, "name" : 3, "salary" : 3, "type" : 2 }

否则在长格式中,由于需要为每个键制作每个文档的副本,因此性能不是很好,如下所示:

db.collection.aggregate([
  { "$project": {
    "name": 1,
    "salary": 1,
    "type": 1,
    "category": { "$literal": ["name","salary","type"] }
  }},
  { "$unwind": "$category" },
  { "$group": {
    "_id": "$category",
    "count": {
      "$sum": {
        "$cond": [
          { "$and": [ 
            { "$eq": [ "$category", "name"] },
            { "$ifNull": [ "$name", false ] }
          ]},
          1,
          { "$cond": [
            { "$and": [
              { "$eq": [ "$category", "salary" ] },
              { "$gte": [ "$salary", 1000 ] }
            ]},
            1,
            { "$cond": [
              { "$and": [
                { "$eq": [ "$category", "type" ] },
                { "$eq": [ "$type", "type2" ] }
              ]},
              1,
              0
            ]}
          ]}
        ]
      }
    }
  }}
])

它的输出:

{ "_id" : "type",   "count" : 2 }
{ "_id" : "salary", "count" : 3 }
{ "_id" : "name",   "count" : 3 }

如果您的文档没有统一的键名或无法指定管道条件中的每个键,请改用mapReduce 申请:

db.collection.mapReduce(
    function() {
        var doc = this;
        delete doc._id;

        Object.keys(this).forEach(function(key) {
          var value = (( key == "salary") && ( doc[key] < 1000 ))
              ? 0
              : (( key == "type" ) && ( doc[key] != "type2" ))
              ? 0
              : 1;

          emit(key,value);
        });
    },
    function(key,values) {
        return Array.sum(values);
    },
    {
        "out": { "inline": 1 }
    }
);

它的输出:

    "results" : [
            {
                    "_id" : "name",
                    "value" : 3
            },
            {
                    "_id" : "salary",
                    "value" : 3
            },
            {
                    "_id" : "type",
                    "value" : 2
            }
    ]

这与条件计数基本相同,只是您只指定所需条件的“反向”,并且只指定要过滤条件的字段。当然,这种输出格式很容易作为单独的文档发出。

相同的方法适用于在您想要条件的字段上测试条件是否满足,并在满足条件的情况下返回 1 或在不求和的情况下返回 0。

【讨论】:

  • 感谢您的清晰解释,它确实对我有很大帮助,并进一步澄清,我如何在 mapReduce 和 中使用“like”条件而不是“equals”聚合函数。
  • @venkat.s 聚合框架没有用于逻辑比较的此类运算符。 mapReduce 是 JavaScript,因此您可以使用正则表达式作为逻辑比较。
【解决方案2】:

您可以使用aggregation 作为以下查询:

db.collection.aggregate({
        $match: {
            salary: 10000,
            //add any other condition here
        }
    }, {
        $group: {
            _id: "$type",
            "count": {
                $sum: 1
            }
        }
    }, {
        $project: {
            "category": "$_id",
            "count": 1,
            _id: 0
        }
    }

【讨论】:

  • 我尝试使用聚合函数,但我可以获得任何一个标准的计数。我想要每个标准字段的计数(例如薪水标准计数,类型标准计数)
  • 根据问题,您可以使用 $facet 进行多重聚合
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-03
  • 2014-11-08
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
相关资源
最近更新 更多