我是Mongodb和spring-data的新手,我在spring数据中使用$cond运算符参考了这个stackoverflow链接分组,并在下面构建了这个代码片段,用于检索Mongodb中的季度销售报告:
String pipeline = "{$project:{_id:1,'unitsSold':1,'dateSold':1,'results': 1 ,
'productName': 1, 'year':{$year:['$dateSold']}, "+
"'quarter':{$cond:[{$lte:[{$month:'$dateSold'},3]},"+
"'first'," +
"{$cond:[{$lte:[{$month:'$dateSold'},6]},"+
"'second',"+
"{$cond:[{$lte[{$month:'$dateSold'},9]},"+"'third',"+
"'fourth']}]}]}}},"+
"{$group:{'_id':{ 'year':'$year', 'quarter':'$quarter'},
'unitsSold': { $sum: '$unitsSold' },'results':{$push:'$$ROOT'}}}";
DBObject operation = (DBObject)JSON.parse (pipeline);
TypedAggregation<SampleReport> aggregation =newAggregation(SampleReport.class,
new DBObjectAggregationOperation(operation)
);
AggregationResults<SampleReport> result =mongoTemplate.aggregate(aggregation, SampleReport.class);
List<SampleReport> list = result.getMappedResults();
for(SampleReport r : list)
{
System.out.println (r.getProductName() + " : " + r.getUnitsSold() + " : " + r.getQuarter() +":: "+r.getYear());
}
问题不在于把销售量加起来。请让我知道我在春季数据中哪里出错了。但是这个查询使用robomongo获得所需的结果。
对
如果您说它在另一个客户端中工作,那么可能在事务中丢失了一些东西。你当然可以在这里清理一些东西,使它更简化。
我通常可以建议一个更有效的"数学"方法来确定当前季度,而不是当前嵌套的条件语句,如果没有别的,它使事情变得更加清晰。除了"效率"之外,你不应该在$group
之前使用$project
,因为简单地将所有内容组合到一个阶段中是合乎逻辑的:
[
{ "$group": {
"_id": {
"year": { "$year": "$dateSold" },
"quarter": {
"$add": [
{ "$subtract": [
{ "$divide": [{ "$subtract": [{ "$month": "$dateSold" },1]},3]},
{ "$mod": [
{ "$divide": [{ "$subtract": [{ "$month": "$dateSold" },1]},3]},
1
]}
]},
1
]
}
},
"unitsSold": { "$sum": "$unitsSold" }
}}
]
如果你真的需要的话,可以通过各种方法添加你的"$push": "$$ROOT"
,但是减少涉及的逻辑并将所有内容放入一个单一的管道阶段,这是合乎逻辑的,这在很大程度上是这里的重点。
下一个阶段是我强烈建议您本地编写此代码。虽然您可能会认为您有一个可以使用的JSON表示法,但您会发现,随着时间的推移,它既不灵活,也不能提供很好的可读性,无法将其放置在长字符串中并依赖于解析它们。此外,您通常需要在某些阶段插入局部变量
Aggregation aggregation = newAggregation(
new CustomGroupOperation(
new BasicDBObject("$group",
new BasicDBObject("_id",
new BasicDBObject("year",new BasicDBObject("$year","$dateSold"))
.append("quarter",new BasicDBObject(
"$add",Arrays.asList(
new BasicDBObject("$subtract",Arrays.asList(
new BasicDBObject("$divide",Arrays.asList(
new BasicDBObject("$subtract",Arrays.asList(
new BasicDBObject("$month","$dateSold"),
1
)),
3
)),
new BasicDBObject("$mod",Arrays.asList(
new BasicDBObject("$divide", Arrays.asList(
new BasicDBObject("$subtract",Arrays.asList(
new BasicDBObject("$month", "$dateSold"),
1
)),
3
)),
1
))
)),
1
)
))
)
.append("unitsSold", new BasicDBObject("$sum", "$unitsSold"))
)
)
);
您似乎也抽象了一些其他代码,但我个人更喜欢以一种不会与在newAggregation
构造中使用其他spring-mongo聚合helper发生冲突的方式实现CustomGroupOperation
:
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);
}
}
但正如最初所说,如果你得到一个0
结果,那么它的字段命名或"类型",其中字段是不同的命名或实际上是一个字符串。但是,相同的语句在任何其他客户端中都可能以类似的方式失败,唯一的补救措施是适当地修复命名或"类型"。
对于你正在做的事情,这当然是一个"更干净"的方法。这种"数学方法"对于一个被指数化的季度来说是合理的,甚至可以通过一个简单的映射来适用于其他"财务季度"。这里的管道阶段整合提供了显著的性能提升,与数据的总体大小一致,因为$project
意味着通过数据进行不必要的传递,只是为了预先调整字段,这是您不想要的。
修复定义和执行,然后检查字段和数据,以确保所有内容都正确命名和键入。