MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,且与关系数据库的最为相像的。它支持的数据结构非常松散,是类似 json 的 bson 格式,因此可以存储比较复杂的数据类型。Mongo 最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
MongoDB 是一个文档数据库,它的数据以文档方式进行存储,将数据存储在类似 JSON 的 BSON 文档中,其特征如下:
数据以 BSON 方式存储
强大的查询语言
拥有关系数据库的所有功能
分布式数据库为核心
MongoDB 免费使用
简单介绍下 MongoDB 的概念知识,方便后续使用 SpringBoot 操作 MongoDB 时候对 MongoDB 相关概念知道其作用。
本文章并不是用于介绍 MongoDB 知识,而是介绍在 Java 语言中 SpringBoot 框架里如何操作 MongoDB。所以,在操作 MongoDB 前,最好对其知识点进行一下系统的学习。
1、基本概念
MongoDB 基本概念指的是学习 MongoDB 最先应该了解的词汇,比如 MongoDB 中的” 数据库”、” 集合”、” 文档” 这三个名词:
2、数据类型
以下为 MongoDB 中常用的几种数据类型:
这里使用 Spring Data MongoDB 封装的 MongoDB 官方 Java 驱动 MongoTemplate 对 MongoDB 进行操作。
关于使用简单的 Repositories 方式来操作 MongoDB 这种用法只能实现较简单的操作,使用简单但是灵活性比较差,所以这里就不介绍这种使用方式了。
1、Maven 引入相关依赖
Maven 引入 SpringBoot 和 MongoDB 相关依赖组件:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.0.RELEASE
mydlq.club
springboot-mongodb-template-example
0.0.1
springboot-mongodb-template-example
Demo project for Spring Boot MongoDB
1.8
org.springframework.boot
spring-boot-starter-web
org.projectlombok
lombok
provided
org.springframework.boot
spring-boot-starter-data-mongodb
org.springframework.boot
spring-boot-maven-plugin
依赖说明:
spring-boot-starter-web: SpringBoot 的 Web 依赖。
lombok: Lombok 工具依赖,便于生成实体对象的 Get 与 Set 方法。
spring-boot-starter-data-mongodb:Spring 对 MongoDb 提供的 Java Drive 封装的框架。
2、Application 文件中添加 MongoDB 连接配置
在 SpringBoot 的 application.yml 文件中添加连接 MongoDB 的配置参数,内容如下:
spring:
data:
mongodb:
host: 127.0.0.1
port: 27017
database: test
username: admin
password: 123456
参数介绍:
spring.data.mongodb.host: 指定 MongoDB Server 地址
spring.data.mongodb.port: 指定 MongoDB Server 端口
spring.data.mongodb.database: 指定使用的数据库
spring.data.mongodb.username: MongoDB 用户名
spring.data.mongodb.password: MongoDB 密码
3、创建用于测试的实体类
创建用于示例中测试的实体 User 和 Status 类:
User.java
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.springframework.data.mongodb.core.mapping.MongoId;
import java.util.Date;
@Data
@ToString
@Accessors(chain = true)
public class User {
/**
* 使用 @MongoID 能更清晰的指定 _id 主键
*/
@MongoId
private String id;
private String name;
private String sex;
private Integer salary;
private Integer age;
@JsonFormat( pattern ="yyyy-MM-dd", timezone ="GMT+8")
private Date birthday;
private String remake;
private Status status;
}
使用 Lombok 中的 @Accessors (chain = true) 注解,能让我们方便使用链式方法创建实体对象。
Status.java
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@ToString
@Accessors(chain = true)
public class Status {
private Integer weight;
private Integer height;
}
4、SpringBoot 启动类
创建 SpringBoot 启动类,方便测试:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@EnableSwagger2
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
5、MongoDB 集合操作
(1)、创建集合
示例代码如下:
import org.springframework.data.mongodb.core.CollectionOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class CreateCollectionService {
@Resource
private MongoTemplate mongoTemplate;
/**
* 创建【集合】
*
* 创建一个大小没有限制的集合(默认集合创建方式)
*
* @return 创建集合的结果
*/
public Object createCollection() {
// 设置集合名称
String collectionName = "users1";
// 创建集合并返回集合信息
mongoTemplate.createCollection(collectionName);
// 检测新的集合是否存在,返回创建结果
return mongoTemplate.collectionExists(collectionName) ? "创建视图成功" : "创建视图失败";
}
/**
* 创建【固定大小集合】
*
* 创建集合并设置 `capped=true` 创建 `固定大小集合`,可以配置参数 `size` 限制文档大小,可以配置参数 `max` 限制集合文档数量。
*
* @return 创建集合的结果
*/
public Object createCollectionFixedSize() {
// 设置集合名称
String collectionName = "users2";
// 设置集合参数
long size = 1024L;
long max = 5L;
// 创建固定大小集合
CollectionOptions collectionOptions = CollectionOptions.empty()
// 创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。
.capped()
// 固定集合指定一个最大值,以千字节计(KB),如果 capped 为 true,也需要指定该字段。
.size(size)
// 指定固定集合中包含文档的最大数量。
.maxDocuments(max);
// 执行创建集合
mongoTemplate.createCollection(collectionName, collectionOptions);
// 检测新的集合是否存在,返回创建结果
return mongoTemplate.collectionExists(collectionName) ? "创建视图成功" : "创建视图失败";
}
/**
* 创建【验证文档数据】的集合
*
* 创建集合并在文档"插入"与"更新"时进行数据效验,如果符合创建集合设置的条件就进允许更新与插入,否则则按照设置的设置的策略进行处理。
*
* * 效验级别:
* - off:关闭数据校验。
* - strict:(默认值) 对所有的文档"插入"与"更新"操作有效。
* - moderate:仅对"插入"和满足校验规则的"文档"做"更新"操作有效。对已存在的不符合校验规则的"文档"无效。
* * 执行策略:
* - error:(默认值) 文档必须满足校验规则,才能被写入。
* - warn:对于"文档"不符合校验规则的 MongoDB 允许写入,但会记录一条告警到 mongod.log 中去。日志内容记录报错信息以及该"文档"的完整记录。
*
* @return 创建集合结果
*/
public Object createCollectionValidation() {
// 设置集合名称
String collectionName = "users3";
// 设置验证条件,只允许岁数大于20的用户信息插入
CriteriaDefinition criteria = Criteria.where("age").gt(20);
// 设置集合选项验证对象
CollectionOptions collectionOptions = CollectionOptions.empty()
.validator(Validator.criteria(criteria))
// 设置效验级别
.strictValidation()
// 设置效验不通过后执行的动作
.failOnValidationError();
// 执行创建集合
mongoTemplate.createCollection(collectionName, collectionOptions);
// 检测新的集合是否存在,返回创建结果
return mongoTemplate.collectionExists(collectionName) ? "创建集合成功" : "创建集合失败";
}
}
(2)、查询集合
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class QueryCollectionService {
@Resource
private MongoTemplate mongoTemplate;
/**
* 获取【集合名称】列表
*
* @return 集合名称列表
*/
public Object getCollectionNames() {
// 执行获取集合名称列表
return mongoTemplate.getCollectionNames();
}
/**
* 检测集合【是否存在】
*
* @return 集合是否存在
*/
public boolean collectionExists() {
// 设置集合名称
String collectionName = "users";
// 检测新的集合是否存在,返回检测结果
return mongoTemplate.collectionExists(collectionName);
}
}
(3)、删除集合
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class RemoveCollectionService {
@Resource
private MongoTemplate mongoTemplate;
/**
* 删除【集合】
*
* @return 创建集合结果
*/
public Object dropCollection() {
// 设置集合名称
String collectionName = "users3";
// 执行删除集合
mongoTemplate.getCollection(collectionName).drop();
// 检测新的集合是否存在,返回删除结果
return !mongoTemplate.collectionExists(collectionName) ? "删除集合成功" : "删除集合失败";
}
}
6、MongoDB 视图操作
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
public class ViewService {
@Resource
private MongoTemplate mongoTemplate;
/**
* 创建视图
*
* @return 创建视图结果
*/
public Object createView() {
// 设置视图名
String newViewName = "usersView";
// 设置获取数据的集合名称
String collectionName = "users";
// 定义视图的管道,可是设置视图显示的内容多个筛选条件
List pipeline = new ArrayList<>();
// 设置条件,用于筛选集合中的文档数据,只有符合条件的才会映射到视图中
pipeline.add(Document.parse("{\"$match\":{\"sex\":\"女\"}}"));
// 执行创建视图
mongoTemplate.getDb().createView(newViewName, collectionName, pipeline);
// 检测新的集合是否存在,返回创建结果
return mongoTemplate.collectionExists(newViewName) ? "创建视图成功" : "创建视图失败";
}
/**
* 删除视图
*
* @return 删除视图结果
*/
public Object dropView() {
// 设置待删除的视图名称
String viewName = "usersView";
// 检测视图是否存在
if (mongoTemplate.collectionExists(viewName)) {
// 删除视图
mongoTemplate.getDb().getCollection(viewName).drop();
return "删除视图成功";
}
// 检测新的集合是否存在,返回创建结果
return !mongoTemplate.collectionExists(viewName) ? "删除视图成功" : "删除视图失败";
}
}
7、MongoDB 文档操作
(1)、文档插入
import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.Status;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
public class InsertService {
/** 设置集合名称 */
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 插入【一条】文档数据,如果文档信息已经【存在就抛出异常】
*
* @return 插入的文档信息
*/
public Object insert() {
// 设置用户信息
User user = new User()
.setId("10")
.setAge(22)
.setSex("男")
.setRemake("无")
.setSalary(1500)
.setName("zhangsan")
.setBirthday(new Date())
.setStatus(new Status().setHeight(180).setWeight(150));
// 插入一条用户数据,如果文档信息已经存在就抛出异常
User newUser = mongoTemplate.insert(user, COLLECTION_NAME);
// 输出存储结果
log.info("存储的用户信息为:{}", newUser);
return newUser;
}
/**
* 插入【多条】文档数据,如果文档信息已经【存在就抛出异常】
*
* @return 插入的多个文档信息
*
*/
public Object insertMany(){
// 设置两个用户信息
User user1 = new User()
.setId("11")
.setAge(22)
.setSex("男")
.setRemake("无")
.setSalary(1500)
.setName("shiyi")
.setBirthday(new Date())
.setStatus(new Status().setHeight(180).setWeight(150));
User user2 = new User()
.setId("12")
.setAge(22)
.setSex("男")
.setRemake("无")
.setSalary(1500)
.setName("shier")
.setBirthday(new Date())
.setStatus(new Status().setHeight(180).setWeight(150));
// 使用户信息加入结合
List userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
// 插入一条用户数据,如果某个文档信息已经存在就抛出异常
Collection newUserList = mongoTemplate.insert(userList, COLLECTION_NAME);
// 输出存储结果
for (User user : newUserList) {
log.info("存储的用户信息为:{}", user);
}
return newUserList;
}
}
(2)、文档存储
import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.Status;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
@Slf4j
@Service
public class SaveService {
/** 设置集合名称 */
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 存储【一条】用户信息,如果文档信息已经【存在就执行更新】
*
* @return 存储的文档信息
*/
public Object save() {
// 设置用户信息
User user = new User()
.setId("13")
.setAge(22)
.setSex("男")
.setRemake("无")
.setSalary(2800)
.setName("kuiba")
.setBirthday(new Date())
.setStatus(new Status().setHeight(169).setWeight(150));
// 存储用户信息,如果文档信息已经存在就执行更新
User newUser = mongoTemplate.save(user, COLLECTION_NAME);
// 输出存储结果
log.info("存储的用户信息为:{}", newUser);
return newUser;
}
}
(3)、文档查询
import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.User;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Service
public class QueryService {
/**
* 设置集合名称
*/
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 查询集合中的【全部】文档数据
*
* @return 全部文档列表
*/
public Object findAll() {
// 执行查询集合中全部文档信息
List documentList = mongoTemplate.findAll(User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【文档ID】查询集合中文档数据
*
* @return 文档信息
*/
public Object findById() {
// 设置查询的文档 ID
String id = "1";
// 根据文档ID查询集合中文档数据,并转换为对应 Java 对象
User user = mongoTemplate.findById(id, User.class, COLLECTION_NAME);
// 输出结果
log.info("用户信息:{}", user);
return user;
}
/**
* 根据【条件】查询集合中【符合条件】的文档,只取【第一条】数据
*
* @return 符合条件的第一条文档
*/
public Object findOne() {
// 设置查询条件参数
int age = 22;
// 创建条件对象
Criteria criteria = Criteria.where("age").is(age);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询一条文档,如果查询结果中有多条文档,那么就取第一条
User user = mongoTemplate.findOne(query, User.class, COLLECTION_NAME);
// 输出结果
log.info("用户信息:{}", user);
return user;
}
/**
* 根据【条件】查询集合中【符合条件】的文档,获取其【文档列表】
*
* @return 符合条件的文档列表
*/
public Object findByCondition() {
// 设置查询条件参数
String sex = "女";
// 创建条件对象
Criteria criteria = Criteria.where("sex").is(sex);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【条件】查询集合中【符合条件】的文档,获取其【文档列表】并【排序】
*
* @return 符合条件的文档列表
*/
public Object findByConditionAndSort() {
// 设置查询条件参数
String sex = "男";
String sort = "age";
// 创建条件对象
Criteria criteria = Criteria.where("sex").is(sex);
// 创建查询对象,然后将条件对象添加到其中,然后根据指定字段进行排序
Query query = new Query(criteria).with(Sort.by(sort));
// 执行查询
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【单个条件】查询集合中的文档数据,并【按指定字段进行排序】与【限制指定数目】
*
* @return 符合条件的文档列表
*/
public Object findByConditionAndSortLimit() {
// 设置查询条件参数
String sex = "男";
String sort = "age";
int limit = 2;
// 创建条件对象
Criteria criteria = Criteria.where("sex").is(sex);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria).with(Sort.by(sort)).limit(limit);
// 执行查询
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【单个条件】查询集合中的文档数据,并【按指定字段进行排序】与【并跳过指定数目】
*
* @return 符合条件的文档列表
*/
public Object findByConditionAndSortSkip() {
// 设置查询条件参数
String sex = "男";
String sort = "age";
int skip = 1;
// 创建条件对象
Criteria criteria = Criteria.where("sex").is(sex);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria).with(Sort.by(sort)).skip(skip);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 查询【存在指定字段名称】的文档数据
*
* @return 符合条件的文档列表
*/
public Object findByExistsField() {
// 设置查询条件参数
String field = "sex";
// 创建条件
Criteria criteria = Criteria.where(field).exists(true);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【AND】关联多个查询条件,查询集合中的文档数据
*
* @return 符合条件的文档列表
*/
public Object findByAndCondition() {
// 设置查询条件参数
String sex = "男";
Integer age = 22;
// 创建条件
Criteria criteriaSex = Criteria.where("sex").is(sex);
Criteria criteriaAge = Criteria.where("age").is(age);
// 创建条件对象,将上面条件进行 AND 关联
Criteria criteria = new Criteria().andOperator(criteriaSex, criteriaAge);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【OR】关联多个查询条件,查询集合中的文档数据
*
* @return 符合条件的文档列表
*/
public Object findByOrCondition() {
// 设置查询条件参数
String sex = "男";
int age = 22;
// 创建条件
Criteria criteriaSex = Criteria.where("sex").is(sex);
Criteria criteriaAge = Criteria.where("age").is(age);
// 创建条件对象,将上面条件进行 OR 关联
Criteria criteria = new Criteria().orOperator(criteriaSex, criteriaAge);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【IN】关联多个查询条件,查询集合中的文档数据
*
* @return 符合条件的文档列表
*/
public Object findByInCondition() {
// 设置查询条件参数
Integer[] ages = {20, 22, 25};
// 创建条件
List ageList = Arrays.asList(ages);
// 创建条件对象
Criteria criteria = Criteria.where("age").in(ageList);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【逻辑运算符】查询集合中的文档数据
*
* @return 符合条件的文档列表
*/
public Object findByOperator() {
// 设置查询条件参数
int min = 25;
int max = 35;
// 创建条件对象
Criteria criteria = Criteria.where("age").gt(min).lte(max);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 根据【正则表达式】查询集合中的文档数据
*
* @return 符合条件的文档列表
*/
public Object findByRegex() {
// 设置查询条件参数
String regex = "^zh*";
// 创建条件对象
Criteria criteria = Criteria.where("name").regex(regex);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
List documentList = mongoTemplate.find(query, User.class, COLLECTION_NAME);
// 输出结果
for (User user : documentList) {
log.info("用户信息:{}", user);
}
return documentList;
}
/**
* 统计集合中符合【查询条件】的文档【数量】
*
* @return 符合条件的文档列表
*/
public Object countNumber() {
// 设置查询条件参数
int age = 22;
// 创建条件对象
Criteria criteria = Criteria.where("age").is(age);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 查询并返回结果
long count = mongoTemplate.count(query, User.class, COLLECTION_NAME);
// 输出结果
log.info("符合条件的文档数量:{}", count);
return count;
}
}
…
(4)、文档更新
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.User;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Slf4j
@Service
public class UpdateService {
/**
* 设置集合名称
*/
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 更新集合中【匹配】查询到的第一条文档数据,如果没有找到就【创建并插入一个新文档】
*
* @return 执行更新的结果
*/
public Object update() {
// 创建条件对象
Criteria criteria = Criteria.where("age").is(30);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 创建更新对象,并设置更新的内容
Update update = new Update().set("age", 33).set("name", "zhangsansan");
// 执行更新,如果没有找到匹配查询的文档,则创建并插入一个新文档
UpdateResult result = mongoTemplate.upsert(query, update, User.class, COLLECTION_NAME);
// 输出结果信息
String resultInfo = "匹配到" + result.getMatchedCount() + "条数据,对第一条数据进行了更改";
log.info("更新结果:{}", resultInfo);
return resultInfo;
}
/**
* 更新集合中【匹配】查询到的【文档数据集合】中的【第一条数据】
*
* @return 执行更新的结果
*/
public Object updateFirst() {
// 创建条件对象
Criteria criteria = Criteria.where("name").is("zhangsan");
// 创建查询对象,然后将条件对象添加到其中,并设置排序
Query query = new Query(criteria).with(Sort.by("age").ascending());
// 创建更新对象,并设置更新的内容
Update update = new Update().set("age", 30).set("name", "zhangsansan");
// 执行更新
UpdateResult result = mongoTemplate.updateFirst(query, update, User.class, COLLECTION_NAME);
// 输出结果信息
String resultInfo = "共匹配到" + result.getMatchedCount() + "条数据,修改了" + result.getModifiedCount() + "条数据";
log.info("更新结果:{}", resultInfo);
return resultInfo;
}
/**
* 更新【匹配查询】到的【文档数据集合】中的【所有数据】
*
* @return 执行更新的结果
*/
public Object updateMany() {
// 创建条件对象
Criteria criteria = Criteria.where("age").gt(28);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 设置更新字段和更新的内容
Update update = new Update().set("age", 29).set("salary", "1999");
// 执行更新
UpdateResult result = mongoTemplate.updateMulti(query, update, User.class, COLLECTION_NAME);
// 输出结果信息
String resultInfo = "总共匹配到" + result.getMatchedCount() + "条数据,修改了" + result.getModifiedCount() + "条数据";
log.info("更新结果:{}", resultInfo);
return resultInfo;
}
}
(5)、文档删除
import com.mongodb.client.result.DeleteResult;
import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Slf4j
@Service
public class RemoveService {
/**
* 设置集合名称
*/
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 删除集合中【符合条件】的【一个]或[多个】文档
*
* @return 删除用户信息的结果
*/
public Object remove() {
// 设置查询条件参数
int age = 30;
String sex = "男";
// 创建条件对象
Criteria criteria = Criteria.where("age").is(age).and("sex").is(sex);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 执行删除查找到的匹配的全部文档信息
DeleteResult result = mongoTemplate.remove(query, COLLECTION_NAME);
// 输出结果信息
String resultInfo = "成功删除 " + result.getDeletedCount() + " 条文档信息";
log.info(resultInfo);
return resultInfo;
}
/**
* 删除【符合条件】的【单个文档】,并返回删除的文档。
*
* @return 删除的用户信息
*/
public Object findAndRemove() {
// 设置查询条件参数
String name = "zhangsansan";
// 创建条件对象
Criteria criteria = Criteria.where("name").is(name);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 执行删除查找到的匹配的第一条文档,并返回删除的文档信息
User result = mongoTemplate.findAndRemove(query, User.class, COLLECTION_NAME);
// 输出结果信息
String resultInfo = "成功删除文档信息,文档内容为:" + result;
log.info(resultInfo);
return result;
}
/**
* 删除【符合条件】的【全部文档】,并返回删除的文档。
*
* @return 删除的全部用户信息
*/
public Object findAllAndRemove() {
// 设置查询条件参数
int age = 22;
// 创建条件对象
Criteria criteria = Criteria.where("age").is(age);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
// 执行删除查找到的匹配的全部文档,并返回删除的全部文档信息
List resultList = mongoTemplate.findAllAndRemove(query, User.class, COLLECTION_NAME);
// 输出结果信息
String resultInfo = "成功删除文档信息,文档内容为:" + resultList;
log.info(resultInfo);
return resultList;
}
}
8、MongoDB 聚合操作
(1)、聚合表达式
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
/**
* 聚合表达式 $group
*
* @author mydlq
*/
@Slf4j
@Service
public class AggregateGroupService {
/**
* 设置集合名称
*/
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 使用管道操作符 $group 结合 $count 方法进行聚合统计
*
* @return 聚合结果
*/
public Object aggregationGroupCount() {
// 使用管道操作符 $group 进行分组,然后统计各个组的文档数量
AggregationOperation group = Aggregation.group("age").count().as("numCount");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group);
// 执行聚合查询
AggregationResults
(2)、聚合管道操作符
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
@Slf4j
@Service
public class AggregatePipelineService {
/**
* 设置集合名称
*/
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 使用 $group 和 $match 聚合,先使用 $match 过滤文档,然后再使用 $group 进行分组
*
* @return 聚合结果
*/
public Object aggregateGroupMatch() {
// 设置聚合条件,先使用 $match 过滤岁数大于 25 的用户,然后按性别分组,统计每组用户工资最高值
AggregationOperation match = Aggregation.match(Criteria.where("age").lt(25));
AggregationOperation group = Aggregation.group("sex").max("salary").as("sexSalary");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(match, group);
// 执行聚合查询
AggregationResults results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $sort 聚合,先使用 $group 进行分组,然后再使用 $sort 排序
*
* @return 聚合结果
*/
public Object aggregateGroupSort() {
// 设置聚合条件,按岁数分组,然后统计每组用户工资最大值和用户数,按每组用户工资最大值升序排序
AggregationOperation group = Aggregation.group("age")
.max("salary").as("ageSalary")
.count().as("ageCount");
AggregationOperation sort = Aggregation.sort(Sort.by("ageSalary").ascending());
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, sort);
// 执行聚合查询
AggregationResults results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $limit 聚合,先使用 $group 进行分组,然后再使用 $limit 限制一定数目文档
*
* @return 聚合结果
*/
public Object aggregateGroupLimit() {
// 设置聚合条件,先按岁数分组,然后求每组用户的工资总数、最大值、最小值、平均值,限制只能显示五条
AggregationOperation group = Aggregation.group("age")
.sum("salary").as("sumSalary")
.max("salary").as("maxSalary")
.min("salary").as("minSalary")
.avg("salary").as("avgSalary");
AggregationOperation limit = Aggregation.limit(5L);
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, limit);
// 执行聚合查询
AggregationResults results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $skip 聚合,先使用 $group 进行分组,然后再使用 $skip 跳过一定数目文档
*
* @return 聚合结果
*/
public Object aggregateGroupSkip() {
// 设置聚合条件,先按岁数分组,然后求每组用户的工资总数、最大值、最小值、平均值,跳过前 2 条
AggregationOperation group = Aggregation.group("age")
.sum("salary").as("sumSalary")
.max("salary").as("maxSalary")
.min("salary").as("minSalary")
.avg("salary").as("avgSalary");
AggregationOperation limit = Aggregation.skip(2L);
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, limit);
// 执行聚合查询
AggregationResults results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $project 聚合,先使用 $group 进行分组,然后再使用 $project 限制显示的字段
*
* @return 聚合结果
*/
public Object aggregateGroupProject() {
// 设置聚合条件,按岁数分组,然后求每组用户工资最大值、最小值,然后使用 $project 限制值显示 salaryMax 字段
AggregationOperation group = Aggregation.group("age")
.max("salary").as("maxSalary")
.min("salary").as("minSalary");
AggregationOperation project = Aggregation.project("maxSalary");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, project);
// 执行聚合查询
AggregationResults results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $unwind 聚合,先使用 $project 进行分组,然后再使用 $unwind 拆分文档中的数组为一条新文档记录
*
* @return 聚合结果
*/
public Object aggregateProjectUnwind() {
// 设置聚合条件,设置显示`name`、`age`、`title`字段,然后将结果中的多条文档按 title 字段进行拆分
AggregationOperation project = Aggregation.project("name", "age", "title");
AggregationOperation unwind = Aggregation.unwind("title");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(project, unwind);
// 执行聚合查询
AggregationResults results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
}
聚合管道操作符:
$project: 可以从文档中选择想要的字段,和不想要的字段(指定的字段可以是来自输入文档或新计算字段的现有字段 ,也可以通过管道表达式进行一些复杂的操作,例如数学操作,日期操作,字符串操作,逻辑操作。
$match: 用于过滤数据,只输出符合条件的文档。$match 使用 MongoDB 的标准查询操作。
$limit: 用来限制 MongoDB 聚合管道返回的文档数。
$skip: 在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind: 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group: 将集合中的文档分组,可用于统计结果。
$sort: 将输入文档排序后输出。
9、MongoDB 索引操作
(1)、创建索引
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Slf4j
@Service
public class CreateIndexService {
/** 设置集合名称 */
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 创建升序索引
*
* @return 索引信息
*/
public Object createAscendingIndex() {
// 设置字段名称
String field = "name";
// 创建索引
return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field));
}
/**
* 创建降序索引
*
* @return 索引信息
*/
public Object createDescendingIndex() {
// 设置字段名称
String field = "name";
// 创建索引
return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.descending(field));
}
/**
* 创建升序复合索引
*
* @return 索引信息
*/
public Object createCompositeIndex() {
// 设置字段名称
String field1 = "name";
String field2 = "age";
// 创建索引
return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field1, field2));
}
/**
* 创建文字索引
*
* @return 索引信息
*/
public Object createTextIndex() {
// 设置字段名称
String field = "name";
// 创建索引
return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.text(field));
}
/**
* 创建哈希索引
*
* @return 索引信息
*/
public Object createHashIndex() {
// 设置字段名称
String field = "name";
// 创建索引
return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.hashed(field));
}
/**
* 创建升序唯一索引
*
* @return 索引信息
*/
public Object createUniqueIndex() {
// 设置字段名称
String indexName = "name";
// 配置索引选项
IndexOptions options = new IndexOptions();
// 设置为唯一索引
options.unique(true);
// 创建索引
return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(indexName), options);
}
/**
* 创建局部索引
*
* @return 索引信息
*/
public Object createPartialIndex() {
// 设置字段名称
String field = "name";
// 配置索引选项
IndexOptions options = new IndexOptions();
// 设置过滤条件
options.partialFilterExpression(Filters.exists("name", true));
// 创建索引
return mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field), options);
}
}
(2)、查询索引
import com.mongodb.client.ListIndexesIterable;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 查询索引操作
*
* @author mydlq
*/
@Slf4j
@Service
public class QueryIndexService {
/** 设置集合名称 */
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 获取当前【集合】对应的【所有索引】的【名称列表】
*
* @return 当前【集合】所有【索引名称列表】
*/
public Object getIndexAll() {
// 获取集合中所有列表
ListIndexesIterable indexList = mongoTemplate.getCollection(COLLECTION_NAME).listIndexes();
// 创建字符串集合
List list = new ArrayList<>();
// 获取集合中全部索引信息
for (Document document : indexList) {
log.info("索引列表:{}",document);
list.add(document);
}
return list;
}
}
(3)、删除索引
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Slf4j
@Service
public class RemoveIndexService {
@Resource
private MongoTemplate mongoTemplate;
/** 设置集合名称 */
private static final String COLLECTION_NAME = "users";
/**
* 根据索引名称移除索引
*/
public void removeIndex() {
// 设置索引名称
String indexName = "name_1";
// 删除集合中某个索引
mongoTemplate.getCollection(COLLECTION_NAME).dropIndex(indexName);
}
/**
* 移除全部索引
*/
public void removeIndexAll() {
// 删除集合中全部索引
mongoTemplate.getCollection(COLLECTION_NAME).dropIndexes();
}
}
10、MongoDB RunCommand 命令操作
(1)、RunCommand 命令
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class RunCommandService {
@Resource
private MongoTemplate mongoTemplate;
/**
* 执行 mongoDB 自定义命令,详情可以查看:https://docs.mongodb.com/manual/reference/command/
*
* @return 执行命令返回结果的 Json 结果
* @description 执行自定义 mongoDB 命令
*/
public Object runCommand() {
// 自定义命令
String jsonCommand = "{\"buildInfo\":1}";
// 将 JSON 字符串解析成 MongoDB 命令
Bson bson = Document.parse(jsonCommand);
// 执行自定义命令
return mongoTemplate.getDb().runCommand(bson);
}
}
注意:单节点 mongodb 不支持事务,需要搭建 MongoDB 复制集。
1、配置事务管理器
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.MongoTransactionManager;
/**
* 配置事务管理器
*
* @author mydlq
*/
@Configuration
public class TransactionConfig {
@Bean
MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
2、创建事务测试服务
import mydlq.club.example.entity.Status;
import mydlq.club.example.entity.User;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
@Service
public class TransactionExample {
/** 设置集合名称 */
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
@Transactional(rollbackFor = Exception.class)
public Object transactionTest(){
// 设置两个用户信息
User user1 = new User()
.setId("11")
.setAge(22)
.setSex("男")
.setRemake("无")
.setSalary(1500)
.setName("shiyi")
.setBirthday(new Date())
.setStatus(new Status().setHeight(180).setWeight(150));
// 插入数据
User newUser1 = mongoTemplate.insert(user1, COLLECTION_NAME);
// 抛出异常,观察数据是否进行回滚
int error = 1/0;
return newUser1;
}
}