👈👈👈 欢迎点赞收藏关注哟
首先分享之前的所有文章 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164...
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca...
一. 前言
日常业务中时不时会用到一些 MongoDB 的查询,慢慢的也累计了不少,索性整理了一下
MongoDB Client 核心原理
思路梳理
- 简单查询 : 通过 find 触发查询,运算符包括 eq 等查询规约
 - 合并查询 : 通过 and , or 做联合查询
 - 高级查询 : MongoDB 提供了大量的查询 ,这些查询在官网都能找到案例
 
Java 使用思路
文章中会穿插对应 Java 的查询写法 ,在日常 Java 开发中对 MongoDB 的使用主要有以下几种 :
- 使用 SpringData Repository 体系进行简单查询
 - 在 SpringData 的基础上使用 ExampleMatcher 进行复杂查询
 - 在 SpringData 的基础上使用 MongoTemplate 进行定制查询
- MongoTemplate 的查询语法主要是 Bson ,以下案例也主要以 Bson 为主
 - Bson 语法可以用于构建和操作 BSON 文档
 
 
二.常用操作
MongoDB 关键字 (官方更加清晰)
- 比较查询 : eq / ge / gte / lt / lte / ne / nin
 - 逻辑查询 : and / or / not / nor
 - 元素查询 : exists / type (查询数据类型)
 - 表达式查询 : expr / jsonSchema / text / where
- mod : 取模查询,查找某个字段的值除以指定的除数后余数等于指定余数的文档
 - regex : 执行正则表达式匹配
 
 - 地理空间查询 :
- near : 离指定地理点最近
 - geoWithin : 查找指定区域内的文档
 - geoIntersects : 与指定区域相交的文档
 - nearSphere : 球面几何查询
 - box : 查询矩形框内的文档
 
 - 数组查询 :
- all : 查找包含指定数组中的所有元素的文档
 - elemMatch : 数组匹配怕, 配置数组中是否包含该字段
 - size : 用于筛选包含指定数组大小的文档
 
 
其他的就不看了,官方文档很清晰。
2.1 简单查询
            
            
              java
              
              
            
          
          // 按照属性查询
db.getCollection("test").find({"name" : "name"})
// 比较运算符
大于 : db.col.find({age : {$gt : 100}})
小于 : db.col.find({age : {$lte : 150}})
区间 : db.col.find({age : {$lt :200, $gt : 100}}) 
数组内 : db.products.find({ category: { $in: ["100", "200"] } })
数组外 : db.products.find({ category: { $nin: ["100", "200"] } })
大于等于 : db.col.find({age : {$gte : 150}})
小于等于 : db.col.find({age : {$lte : 150}})
等于 : db.col.find({age : {$eq : 150}})
不等于 : db.col.find({age : {$ne : 150}})
// Java 写法========
Bson bson = Filters.eq("username", "XDJHD20230517173938");
        简单筛选
            
            
              java
              
              
            
          
          // 去重
db.users.distinct("username")
        分页和排序
            
            
              java
              
              
            
          
          // 分页查询
db.users.find().sort({"username":1}).limit(2).skip(2)
// 排序查询
db.col.find({},{"title":1,_id:0}).sort({"likes":-1})   
// Java 写法========
Bson sortBs = Sorts.descending("createTime");
mongoTemplate.getCollection(COLLECTION).find(bson).limit(10).skip(1).sort(sortBs);
        2.2 高级查询
AND 语句
            
            
              java
              
              
            
          
          db.users.find({"$and":[{"username":"gang"},{"age":18}]},{"username":0,"age":
0})
// Java 写法========
Bson bson = Filters.and(
        Filters.eq("fieldA", "A"),
        Filters.eq("fieldB", "B")
);
        OR 语句
            
            
              java
              
              
            
          
          db.users.find( { $or: [{"year" : 1989}, {"username" :"gang"}] } )
// Java 写法============
Bson bson = Filters.and(
        Filters.or("fieldA", "A"),
        Filters.or("fieldB", "B")
);
// 稍微复杂点的合并查询
Bson bsonOr = Filters.or(
        Filters.eq("fieldA", "A"),
        Filters.eq("fieldB", "B")
);
Bson bsonAnd = Filters.and(
        bsonOr,
        Filters.eq("fieldC", "C"),
        Filters.eq("fieldD", "D")
);
        模糊正则匹配
            
            
              java
              
              
            
          
          // 使用正则查询
db.users.find({ "fieldA": /.*230517.*/i }).limit(10).skip(0)
db.users.find( { "username" : /^B/} )
// Java 写法============
Bson bsonAnd = Filters.regex("fieldA", "230517");
Bson bsonAnd = Filters.regex("fieldA", "^TEST\d*0517
Bson bsonAnd = Filters.regex("planCode", ".*230517.*");
        PS :不管是原生语法还是Java写法,都可以通过正则表达式实现一定的模糊查询
- 但是切记!!模糊有风险,在没有命中主数据体的情况下,可能会把数据库跑崩!!
2.3 增删改操作
文档的插入
            
            
              java
              
              
            
          
          db.products.insertOne( { item: "card", qty: 15 } );
db.products.insertMany( [ { _id: 10, item: "large box",
qty: 20 }, { _id: 11, item: "smallbox", qty: 55 }, { _id: 12, item: "medium box", qty: 30 }
] );
db.collection.insert
        2.4 数据库管理
集合的创建
            
            
              java
              
              
            
          
          // 创建一个集合
db.createCollection("runoob")
    
// 创建指定大小的集合 (size : 空间大小 , max : 文档个数 )
db.createCollection("mycol", { capped : true, autoIndexId : true, size : 6142800, max : 10000 } )    
// 删除集合 mycoll
db.mycoll.drop()
        三. 高级用法
3.1 聚合查询
聚合查询主要是通过 $group语法根据指定的字段进行分组,并使用$sum、$avg、$min、$max等操作符进行计算。
            
            
              java
              
              
            
          
          // group 查询语法
{
    $group: {
        _id: <expression>, // 分组条件,通常是一个字段或表达式
        <field1>: { <accumulator1>: <expression1> }, // 聚合操作1
        <field2>: { <accumulator2>: <expression2> }, // 聚合操作2
        ...
    }
}
// 参数含义
- _id : 指定用于分组的条件,通常是一个字段的名称或表达式
- field : 要进行聚合操作的字段
- accumulator  : 聚合函数
- expression :聚合操作函数的参数,通常是一个字段名称或表达式,指定要进行聚合操作的字段或计算条件
        accumulator 语法 :
- $sum:计算指定字段的总和。例如,计算销售总额或数量总和
 - $avg:计算指定字段的平均值。例如,计算平均销售价格或平均评分
 - $max:找到指定字段的最大值。例如,找到最高温度记录
 - $min:找到指定字段的最小值。例如,找到最低库存量
 - $first:返回分组内第一个文档的指定字段的值
 - $last:返回分组内最后一个文档的指定字段的值
 - $push:将匹配文档的指定字段值添加到数组中
 - $addToSet:将匹配文档的指定字段值添加到一个集合中,去重复
 
使用案例 - expression 表达式的作用
expression 的存在让聚合查询存在了更多的可能性 , 总体来说有2种处理方式 :
            
            
              java
              
              
            
          
          // 统计分组的文档数量 (按照 type 进行分组)
db.user.aggregate([
    {
        $group: {
            _id: "$type",  
            count: { $sum: 1 } 
        }
    }
]);
// 同时进行多个统计
db.user.aggregate([
    {
        $group: {
            _id: "$type",
            totalAge: { $sum: "$age" },       // 计算总和
            avgAge: { $avg: "$age" }          // 计算平均值
        }
    }
]);
// 条件表达式查询 (获取年龄大于50的总数)
db.user.aggregate([
    {
        $group: {
            _id: "$type",
            highSalesCount: {
                $sum: { $cond: { if: { $gte: ["$age", 50] }, then: 1, else: 0 } }
            }
        }
    }
]);
        3.2 其他常用函数用法
            
            
              java
              
              
            
          
          // 按照类型查询 : (查询包含Double类型的数据)
db.collection.find({ field: { $type: 1 } })
> 类型 : https://www.mongodb.com/docs/manual/reference/operator/query/type/#mongodb-query-op.-type
// all 数组查询
- 查询包含 abc 和 edf 2个名字的所有文档
db.user.find({ username: { $all: ["abc", "edf"] } })
// 查询包含 exactly 3 个标签的文章
db.articles.find({ tags: { $size: 3 } })
// 取模查询 - 查询所有余数为 0 的偶数文档
db.numbers.find({ value: { $mod: [2, 0] } })
// 正则表达式匹配 - 以 A开头的文档
db.collection.find({ name: { $regex: /^A/ } })
        四. Java 用法
所有的 DB 库基本上都能通过实现对应的 Repository 来实现对 DB 实例的调用 ,使用方式极其简单 :
            
            
              java
              
              
            
          
          @Repository
public interface SelectUserDas extends MongoRepository<UserDto, Long> {
    /**
     * 通过 userCode 进行删除
     */
    int deleteByCode(String userCode);
}
        使用的时候基于 MongoRepository 能完成80%的功能,这一块文档很多,就不看了。我们要弄清除的是那剩下的20%
BSON 查询语法
            
            
              java
              
              
            
          
          // 构建 BSON 查询语句
Bson sortBs = Sorts.descending("createTime"); Bson bson = Filters.eq("userCode", "DemoTest"); 
// find 中传入查询语句
FindIterable<Document> collect = mongoTemplate.getCollection(COLLECTION).find(bson).limit(10).skip(1).sort(sortBs);
        Spring 使用过程中还是基于 Repository 的 Example 语法 :
            
            
              java
              
              
            
          
          <S extends T> Page<S> findAll(Example<S> var1, Pageable var2);
// 使用方式
ExampleMatcher matcher = ExampleMatcher.matching()
    .withMatcher("username", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
    .withMatcher("usercode", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase());
Example<UserDo> example = Example.of(selectDto);
Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
Pageable pageable = PageRequest.of(
pageDto.getPageNum() - NumberConstant.CONSTANT_1, pageDto.getPageSize(), sort);
Page<UserDo> userPageDto = selectionResultDas.findAll(example, pageable);
        聚合查询
            
            
              java
              
              
            
          
          @Resource
private MongoTemplate mongoTemplate;
@GetMapping("get")
public String agg() {
    // 定义聚合操作:按产品名称分组,并计算总销售额和平均销售金额
    GroupOperation groupOperation = Aggregation.group("type")
            .sum("age").as("totalAge")
            .avg("age").as("avgAge");
    // 构建聚合查询
    TypedAggregation<User> aggregation = Aggregation.newAggregation(User.class, groupOperation);
    // 执行聚合查询
    AggregationResults<JSONObject> result = mongoTemplate.aggregate(aggregation, JSONObject.class);
    // 获取聚合结果
    List<JSONObject> productSalesStatsList = result.getMappedResults();
    log.info("------> {} <-------", productSalesStatsList);
    return "sccuess";
}
        这种方式基本上能解决99的问题,更复杂的可以看之前的一篇文章 juejin.cn/post/725325... ,里面详细说明了 MongoDB Client 的配置和使用方式。
总结
东西不多,简单记下。