2015-11-03 83 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) 
相關問題