首頁 > 軟體

使用mongoTemplate實現多條件加分組查詢方式

2022-06-30 14:00:57

先來一個常見的錯誤資訊:

Due to limitations of the com.mongodb.BasicDocument, you can't add a second '$and' expression specified as '$and : 

錯誤原因:

在一個 Criteria 物件中呼叫了多次 andOperator() 方法

mongoTemplate實現多條件查詢

多個條件的查詢只需要建立 Query 物件,然後把需要新增的條件使用 Query 物件的 addCriteria() 方法

// 場景:查詢指定時間段內,狀態為1的資料
// 入參條件 :beginTime ,endTime ,statue
// mongodb欄位:time , state
 
// 存放條件的物件
Query condition= new Query();
 
// 判斷時間是否為空
if(beginTime != null && endTime != null){
    // 新增大於開始時間小於結束時間的條件
    condition.addCriteria(Criteria.where("time").gte(beginTime).lte(endTime));
}else{
    // 其中一個為空 分別進行判斷
    if(beginTime != null){
        condition.addCriteria(Criteria.where("time").gte(beginTime));
    }
    if(endTime != null){
        condition.addCriteria(Criteria.where("time").lte(endTime));
    }
}
 
// 新增狀態為1條件
if(statue!=null){
    condition.addCriteria(Criteria.where("state").is(statue));
}

條件有了後再呼叫 mongoTemplate.find(condition,返回型別.class,collectionName)

但是...想要分組,得呼叫 mongoTemplate.group(Criteria criteria , String inputCollectionName , GroupBy groupBy , Class<T> entityClass) 方法 (不是說只能這樣才能分組,而是我通過這種方法實現了分組查詢)

朋友們,第一個引數條件只能入參 Criteria 物件,而不能入參 Query 物件

結果我發現 Criteria 物件有 andOperator(Criteria ... criteria) 方法

這個方法就厲害了,可以入引陣列,也就是說

我們可以把查詢條件先存放到一個集合裡面(因為陣列需要定義長度,如果條件個數不確定,就不能直接定義陣列),然後把集合放入陣列中,再把陣列入參 andOperator(Criteria ... criteria) 方法

// 場景:查詢指定時間段內,狀態為1的資料
// 入參條件 :beginTime ,endTime ,statue
// mongodb欄位:time , state
 
// 定義一個存放條件的集合
List<Criteria> criteriaList = new ArrayList<>();
// 定義一個存放條件的陣列(暫時不給長度)
Criteria[] criteriaArray = {};
 
// 判斷時間是否為空
if(beginTime != null && endTime != null){
    // 新增大於開始時間小於結束時間的條件
    Criteria between = Criteria.where("time").gte(beginTime).lte(endTime);
    criteriaList.add(between);
}else{
    // 其中一個為空 分別進行判斷
    if(beginTime != null){
        Criteria gte = Criteria.where("time").gte(beginTime);
        criteriaList.add(gte);
    }
    if(endTime != null){
        Criteria lte = Criteria.where("time").lte(endTime);
        criteriaList.add(lte);
    }
}
 
// 新增狀態為1條件
if(statue!=null){
    Criteria isState = Criteria.where("state").is(statue);
    criteriaList.add(isState);
}
 
// 如果有條件
if(criteriaList.size()>0){
  // 集合的個數就是陣列的長度
  criteriaArray = new Criteria[criteriaList.size()];
  // 遍歷新增到陣列中
  for(int i = 0 ; i<criteriaList.size(); i++){
      criteriaArray[i] = criteriaList.get(i);
   }
}
 

這種就可以呼叫 mongoTemplate.group(Criteria criteria , String inputCollectionName , GroupBy groupBy , Class<T> entityClass) 方法進行分組查詢了

 GroupBy groupBy = new GroupBy("分組欄位")
                    .initialDocument("{ count: 0 }")
                    .reduceFunction("function (doc,pre){pre.count +=1 ;}");
 
// new Criteria().andOperator(criteriaArray) 這個是很關鍵的一步操作,把剛剛的條件陣列放入進入
// groupByResults 這個物件裡面內容很多,有興趣的朋友可以斷點進入看一下
GroupByResults groupByResults = mongoTemplate.
                    group(new Criteria().andOperator(criteriaArray), mongodb的collectionName, groupBy, 實體類.class);
// 獲取分組後的數量
long resultCount = ((List)groupByResults.getRawResults().get("retval")).size();

mongoTemplate分組查詢的坑

Aggregation agg = Aggregation.newAggregation(
                Aggregation.match(new Criteria().orOperator(new Criteria("to").is(ukey), new Criteria().and("fromAccount").is(ukey))),
                Aggregation.sort(Sort.Direction.DESC,"_id"),
                Aggregation.group("to","fromAccount")
        );

Aggregation.group 要排在Aggregation.match後面,否則結果集不準確。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com