java - 根据条件分组和求和

标签 java mongodb mongodb-query aggregation-framework mongotemplate

我使用 mongoTemplate 查询我的 mongodb 数据库,我想在我的集合中做一些计数。我想按 id 分组并包括有条件的计数。我在 mongoshell 中使用了这个查询

db.scenarios.aggregate([
    { $match: { bid: "build_1481711758" } },
    {
        $group: {
            _id: "$bid",
            nb: { $sum: 1 },
            nbS: {
                "$sum": {
                    "$cond": [
                        { "$eq": ["$scst",  true ] },  
                        1, 0 
                    ]
                }
            },
            nbE: {
                "$sum": {
                    "$cond": [
                        { "$eq": ["$scst",  false ] },  
                        1, 0 
                    ]
                }
            }
        }
    }
])

它返回我想要的,但我不知道如何将它转换为 java mongotemplate。

请帮忙:)

最佳答案

您可以将管道简化为

db.scenarios.aggregate([
    { $match: { bid: "build_1481711758" } },
    {
        $group: {
            _id: "$bid",
            nb: { $sum: 1 },
            nbS: {
                "$sum": {
                    "$cond": [ "$scst",  1, 0 ]
                }
            },
            nbE: {
                "$sum": {
                    "$cond": [ "$scst",  0, 1 ]
                }
            }
        }
    }
])

自从 $cond 运算符计算一个 boolean 表达式以返回两个指定返回表达式之一,并且 scst 字段默认返回一个 boolean 值。

如果使用支持 $cond 的当前 Spring Data 版本 运算符通过 $project 管道,然后可以将其转换为(未测试):

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.*;
import org.springframework.data.mongodb.core.query.Criteria;

Cond operatorNbS = ConditionalOperators.when("scst").thenValueOf(1).otherwise(0);
Cond operatorNbE = ConditionalOperators.when("scst").thenValueOf(0).otherwise(1);

Aggregation agg = newAggregation(
    match(Criteria.where("bid").is("build_1481711758"),
    project("bid") 
        .and("scst")                            
        .applyCondition(operatorNbE, field("nbE"))
        .applyCondition(operatorNbS, field("nbS"))
    group("bid")
        .count().as("nb")
        .sum("nbE").as("nbS")
        .sum("nbE").as("nbE") 
);
AggregationResults<Scenarios> results = mongoTemplate.aggregate(agg, Scenarios.class); 
List<Scenarios> scenarios = results.getMappedResults();

如果您的 Spring Data 版本不支持此功能,解决方法是实现 AggregationOperation 接受 DBObject 的接口(interface):

public class CustomGroupOperation implements AggregationOperation {
    private DBObject operation;

    public CustomGroupOperation (DBObject operation) {
        this.operation = operation;
    }

    @Override
    public DBObject toDBObject(AggregationOperationContext context) {
        return context.getMappedObject(operation);
    }
}

然后执行 $group作为聚合管道中的 DBObject 操作,与您拥有的相同:

DBObject operation = (DBObject)new BasicDBObject(
    "$group", new BasicDBObject(
        "_id", "$bid"
    )
    .append( "nb", new BasicDBObject("$sum", 1) )
    .append(
        "nbS", new BasicDBObject(
            "$sum", new BasicDBObject(
                "$cond", new Object[]{ "$scst", 1, 0 }
            )
        )
    ).append(
        "nbE", new BasicDBObject(
            "$sum", new BasicDBObject(
                "$cond", new Object[]{ "$scst", 0, 1 }
            )
        )
    )
);

然后您可以将其用作:

Aggregation agg = newAggregation(
    match(Criteria.where("bid").is("build_1481711758"),
    new CustomGroupOperation(operation)
);

要获得执行速度比上述方法快得多的更灵活、性能更好的方法,请考虑如下运行替代管道

 db.scenarios.aggregate([
    { $match: { bid: "build_1481711758" } },
    { 
        "$group": {
            "_id": { 
                "bid": "$bid",
                "scst": "$scst"
            },
            "count": { "$sum": 1 }
        }
    },
    { 
        "$group": {
            "_id": "$_id.bid",
            "counts": {
                "$push": {
                    "scst": "$_id.scst",
                    "count": "$count"
                }
            }
        }
    }
])

关于java - 根据条件分组和求和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41218321/

相关文章:

java - 黑莓图书馆问题。 (jre6 + NET_RIM_BLACKBERRY)

java - R 绘图的问题

node.js - 有什么方法可以存储nodejs应用程序所做的所有交易吗?

node.js - 根据条件从现有字段计算分数

java - Android 9.0 (Pie) 不支持异步任务

java - 接口(interface)方法可以重载吗?

javascript - 如何将一个集合字段合并到另一个集合字段而不重复

node.js - 通过 mongodb 和 mongoose 中的 id 删除对象

mongodb - Mongo - 匹配对象键可变的地方

c# - MongoDB .NET 驱动程序 - 聚合组和计数