2015-11-03 55 views
2

我在MongoDB中有一个聚合查询,当我在shell中直接运行它时会起作用。这里的壳查询:如何在Spring中编写Mongo聚合查询?

db.MyCollection.aggregate([ 
    {$match: {_id: {$in: ['A', 'B', 'C']}}}, 
    {$project: {"versions": "$nested.field.version"}}, 
    {$unwind: "$versions"}, 
    {$group: {_id: "$_id", "maxVersion": {$max: "$versions"}}} 
]) 

因此,大家可以看到,这个执行以下操作:

  1. 只匹配与指定ID的某些文件
  2. 项目嵌套场下降到基层现场(并有效地过滤掉管道中的所有其他字段,但仍保留ID)
  3. 展开我们投射到流水线中单个文档中的$ versions字段的数组元素
  4. 查找每个ID的这些$版本的最大值

就像我说的那样,上面的查询已经有效。我的问题是如何将它翻译成Spring MongoDB语法。这是我第一次尝试,这确实不工作

Aggregation aggregation = newAggregation(
    match(Criteria.where("_id").in(listOfIds)) 
    ,project().and("versions").nested(bind("versions", "nested.field.version")) 
    ,unwind("versions") 
    ,group("_id").max("versions").as("maxVersion") 
); 

当我尝试运行在调试模式下的代码,我可以看到我居然得到newAggregation一个IllegalArgumentException说,它不能评估。如果我注释掉与$ group子句行的话,我可以看到这个的toString()聚集变量的表现,揭示与$项目第一个问题:

{ 
    "aggregate" : "__collection__" , 
    "pipeline" : [ 
    { "$match" : { "_id" : { "$in" : [ "A" , "B" , "C"]}}} , 
    { "$project" : { "versions" : { "versions" : "$nested.field.version"}}} , 
    { "$unwind" : "$versions"} 
    ] 
} 

显然,这不匹配我的意图是什么,所以我没有得到正确的语法。但TBH我没有发现Spring MongoOps语法非常直观,而且他们的文档也不是很好。

我没有看到任何方式调用nested()方法,但没有包括对and()的调用。我认为这是主要问题,因为它在那里嵌套倍增。在这里有没有任何Spring MongoOps英雄能够帮助我正确地编写相应的Java代码?

编辑:这里是我使用收集的快照:robomongo display

回答

6

$project管道是没有必要的,因为你仍然可以在嵌套领域做一个$unwind,因此这种聚合管道可以产生与您目前相同的结果:

db.MyCollection.aggregate([ 
    { 
     "$match": { 
      "_id": { "$in": ['A', 'B', 'C'] } 
     } 
    }, 
    { "$unwind": "$nested.field" }, 
    { 
     "$group": { 
      "_id": "$_id", 
      "maxVersion": { "$max": "$nested.field.version" } 
     } 
    } 
]) 

Spring Data MongoDB聚合等效项:

Aggregation agg = newAggregation(
     match(Criteria.where("_id").in(ids)), 
     unwind("nested.field"),   
     group("_id").max("nested.field.version").as("maxVersion") 
    ); 

返回到当前的聚集,需要$unwindnested.field阵列,因为这不是nested.field.version字段是一个字符串,而不是数组:

db.MyCollection.aggregate([ 
    {$match: {_id: {$in: ['A', 'B', 'C']}}}, 
    {$project: {"fields": "$nested.field"}}, 
    {$unwind: "$fields"}, 
    {$group: {_id: "$_id", "maxVersion": {$max: "$fields.version"}}} 
]) 

的Sprind数据的MongoDB等效会是什么样子:

Aggregation agg = newAggregation(
     match(Criteria.where("_id").in(ids)), 
     project().and("nested.field").as("fields") 
     unwind("fields"),   
     group("_id").max("fields.version").as("maxVersion") 
    ); 
+2

那么,您的答案在这里是正确的。不幸的是,尽管由于Spring Data的一个bug,但它并不适用于我的特殊情况。我总是在发布SO之前清理我的字段名称,但实际上我在某些嵌套字段名称中强调了下划线,看起来Spring Data在进行一些引用失败的参照完整性检查时会对下划线进行某种分割。所以感谢您的努力,但不幸的是,Spring Data对于我的用例来说太麻烦了。 – SoaperGEM

+0

@SoaperGEM不用担心,太糟糕了,不适合你。 – chridam

0

在修正下划线错误之前使用map reduce方式。 像:

GroupBy groupBy = GroupBy.key("user_id") 
     .initialDocument("{ total : 0, used : 0 }") 
     .reduceFunction("function(curr, result){ result.total++; if(curr.status == 1) {result.used++;} result.userID = curr.user_id;"); 
     GroupByResults<YourResult> yourResultInfo = 
       mongoTemplate.group(Criteria.where("user_id").in(user_ids), 
           "your_collection_name", groupBy, YourResult.class); 

class YourResult{ 
private String userID; 
    private Long total = 0l; 
    private Long used = 0l; 
// getter and setter`enter code here 
} 
0

Spring使用_作为野车的数组和分裂snake_case领域,当表演场合计运作参考验证。

为了避免验证,您可以使用下面的MongoTemplate方法执行聚合,但不进行字段转换和验证。

public <O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType) 
相关问题