根据条件分组和求和
Grouping and Sum with Conditions
我使用 mongoTemplate 查询我的 mongodb 数据库,我想在我的 collections 中进行一些计数。我想按 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
]
}
}
}
}
])
它 returns 我想要的,但我不知道如何将它转换为 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
运算符将布尔表达式计算为 return 两个指定的 return 表达式之一和 scst
字段默认 return 是一个布尔值。
如果使用支持 $cond
operator via the $project
管道的当前 Spring 数据版本,则可以将其转换为(未测试):
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 数据版本不支持此功能,解决方法是实现 AggregationOperation 接口以接收 DBObject
:
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"
}
}
}
}
])
我使用 mongoTemplate 查询我的 mongodb 数据库,我想在我的 collections 中进行一些计数。我想按 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
]
}
}
}
}
])
它 returns 我想要的,但我不知道如何将它转换为 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
运算符将布尔表达式计算为 return 两个指定的 return 表达式之一和 scst
字段默认 return 是一个布尔值。
如果使用支持 $cond
operator via the $project
管道的当前 Spring 数据版本,则可以将其转换为(未测试):
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 数据版本不支持此功能,解决方法是实现 AggregationOperation 接口以接收 DBObject
:
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"
}
}
}
}
])