Spring Data Mongodb的Criteria类(all、and、andOperator、elemMatch)

扒皮狼

关注

阅读 89

2021-09-28

[](javascript:void(0); "添加到收藏夹")

Criteria类提供了以下方法,所有这些方法都对应于MongoDB中的运算符:

1. all条件的使用

  db.inventory.insert([  
    {item: "小兔", qty: 25, tags: ["黑", "灰","白"], dim_cm: [ 14, 21 ] }, 
    {item: "大狼", qty: 25, tags: ["黑", "灰"], dim_cm: [ 10, 22 ]},
    {item: "大象", qty: 25, tags: ["灰", "黑"], dim_cm: [ 14, 25 ]},  
    {item: "小鸟", qty: 25, tags: ["黑"], dim_cm: [ 5, 9 ]}
  ]);

匹配数组时,若文档中数组个数和顺序不满足要求时,无法进行匹配。使用$all关键字可以取消该限制。

 public static void find9() {
        Criteria criteria = Criteria.where("tags").all("黑", "灰");
        Query query = Query.query(criteria);
        log.info("流程:{}", query);
        List<BasicDBObject> basicDBObjects = mongoTemplate.find(query,
                BasicDBObject.class, "inventory");
        log.info("最终数据{}", JSON.toJSONString(basicDBObjects));
    }

相当于

{ "tags" : { "$all" : ["黑", "灰"] } }

2. and条件的使用

 public static void find9() {
        Criteria criteria = Criteria.where("qty").is("25").and("item").is("小兔");
        Query query = Query.query(criteria);
        log.info("流程:{}", query);
        List<BasicDBObject> basicDBObjects = mongoTemplate.find(query,
                BasicDBObject.class, "inventory");
        log.info("最终数据{}", JSON.toJSONString(basicDBObjects));
    }

相当于

{ "qty" : "25", "item" : "小兔" }

3. andOperator的使用

andOperator解决的是查询的是同一个字段多个约束的问题,会生成$and操作符

//一个元素要大于28并且它的数组长度大于2位吗(会抛出异常)
//Criteria criteria = Criteria.where("qty").gt(28).and("qty").size(2);  
//解决了查询同一个字段多个约束的问题,注意需要在Mongo2.0版本及以上。  
Criteria criteria = new Criteria().andOperator(  
        Criteria.where("qty").gt(28),  
        Criteria.where("qty").size(2)  
);  

相当于

{ "$and" : [{ "qty" : 25 }, { "item" : "小兔" }] }

4. elemMatch的使用

默认情况下,多条件查询一个数组。文档内的数组一个元素满足所有条件,也可以是每个元素只满足一部分条件但加起来满足所有条件。使用$elemMatch操作符表示要求数组中至少一个元素满足所有条件。

4.1 内联数字数组

案例一:寻找成绩大于80小于90的数组。如果不使用elemMatch的话,文档数组中的每个元素只满足一部分条件但加起来满足所有条件即可。

   db.testelemMatch.insert([
    { "name" :"数组1" , "score" : [70.0 , 80.0 , 100.0]},
    { "name" :"数组2" , "score" : [ 120.0 , 60.0]},
    { "name" :"数组2" , "score" : [ 88.0 , 99.0]},
    { "name" :"数组2" , "score" : [ 18.0 , 59.0]},
    { "name" :"数组2" , "score" : [ 28.0 , 79.0]},
    { "name" :"数组3" , "score" : [ 48.0 , 89.0]}
   ])

若不使用elemMatch,那么60小于90,120大于80,数组2也会输出。

Criteria c1 = Criteria.where("$gt").is(80).and("$lt").is(90);  
Query query = new Query(Criteria.where("score").elemMatch(c1));  
//映射关系,该元素会被映射。  
query.fields().include("score");  
Query: { "score" : { "$elemMatch" : { "$gt" : 80, "$lt" : 90 } } }, 
Fields: { "score" : 1 }, 
Sort: { }

得到的数据:

[{"_id":"5e68d1ba1ec58cc4b94b7a8d","score":[88,99]},
{"_id":"5e68d1ba1ec58cc4b94b7a90","score":[48,89]}]

案例二:其中members是一个数组,包含的是每个群组成员的ID,假设要查询ID是2的用户参与的组。

   db.testelemMatch2.insert(
   [{"_id":0, "members":[1,3,4,5,6,7]},
   {"_id":1,"members":[2,4,6,8,11,13]},
   {"_id":2,"members":[1,7,6,4]}]
   )
Criteria criteria = Criteria.where("members").is(2);
Query query = Query.query(criteria);        
log.info("流程:{}", query);
List<BasicDBObject> basicDBObjects = mongoTemplate.find(query, 
                BasicDBObject.class, "testelemMatch2");
log.info(JSON.toJSONString(basicDBObjects));

实际的执行语句:

db.testelemMatch2.find({ "members" : 2 });

4.2 内联对象数组

案例三:将key=area,value=IT的对象所在的文档筛选出来。

   db.testelemMatch3.insert([
    {"find": "project1","tags": [{"key": "area", "value": "IT"},{"key": "department", "value": "Architecture"}]},
    {"find": "project2","tags": [{"key": "area", "value": "HR"},{"key": "department", "value": "IT"}]}
   ])

正确案例:

public static void find9() {  
    Criteria criteria1 = Criteria.where("key").is("area").and("value").is("IT");  
    Criteria criteria = Criteria.where("tags").elemMatch(criteria1);  
    Query query = Query.query(criteria);  
    log.info("流程:{}", query);  
    List<BasicDBObject> basicDBObjects = mongoTemplate.find(query,  
            BasicDBObject.class, "testelemMatch3");  
    log.info(JSON.toJSONString(basicDBObjects));  
}  

最终输出的原生语句:

{ "tags" : { "$elemMatch" : { "key" : "area", "value" : "IT" } } }

错误案例:

内置文档数组默认是一个元素满足所有条件也可以每个元素只满足一部分条件但加起来满足所有条件。

内联数组的两个文档均满足部分的key=area,value=IT条件,也可以完成筛选。

    public static void find9() {   
        //对文档进行筛选
        Criteria criteria = Criteria.where("tags.key").is("area").and("tags.value").is("IT");
        log.info("流程:{}", query);
        List<BasicDBObject> basicDBObjects = mongoTemplate.find(query,
                BasicDBObject.class, "testelemMatch3");
        log.info("最终数据{}", JSON.toJSONString(basicDBObjects));
    }

最终输出的原生语句:

 { "tags.key" : "area", "tags.value" : "IT" }

推荐阅读

spring mongodb Criteria中"and"与"andOperator"方法的区别及"$and"如何工作

Spring Data Mongodb的官方文档

java 中使用Criteria 进行mongodb的各种操作 模糊查询 精确查询 等等

精彩评论(0)

0 0 举报