👈👈👈 欢迎点赞收藏关注哟
首先分享之前的所有文章 >>>> 😜😜😜
文章合集 : 🎁 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 的配置和使用方式。
总结
东西不多,简单记下。