SpringBoot整合MongoDB全过程
作者:一只咸鱼。。
一、环境准备
①添加 SpringData 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
②配置 yml 文件,官方连接配置文档
方式一:
spring: data: mongodb: uri: mongodb://root:123456@1.15.76.95:27017/library?authSource=admin
方式二:
spring: data: mongodb: username: root password: 123456 host: 1.15.76.95 port: 27017 database: library authentication-database: admin
③直接注入 MongoTemplate 进行操作
@Resource MongoTemplate mongoTemplate;
二、集合操作
@Test public void testCollection(){ boolean exists = mongoTemplate.collectionExists("borrow"); if(exists) { // 删除集合 mongoTemplate.dropCollection("borrow"); }else { // 创建集合 mongoTemplate.createCollection("borrow"); } Set<String> collectionNames = mongoTemplate.getCollectionNames(); System.out.println(collectionNames.toString()); // [borrow, book, user] }
三、文档操作
3.1 实体类
@Document
- 修饰范围:用在类上。
- 作用:用来映射这个类的一个对象为 Mongo 中一条文档数据。
- 属性:(value 、collection) 用来指定操作的集合名称。
@MongoId
- 修饰范围:用在成员变量、方法上。
- 作用:用来将成员变量的值映射为文档的 _id 的值。
@Field
- 修饰范围:用在成员变量、方法上。
- 作用:用来将成员变量及其值映射为文档中一个 key:value 对。
- 属性:(name , value) 用来指定在文档中 key 的名称,默认为成员变量名。
@Transient
- 修饰范围:用在成员变量、方法上。
- 作用:用来指定此成员变量不参与文档的序列化。
@Data @AllArgsConstructor @NoArgsConstructor @Document("user") public class User { @MongoId private Integer uid; @Field private String name; @Field private String password; @Field private Integer age; }
3.2 添加文档
insert 方法返回值是新增的 Document 对象,里面包含了新增后 id 的值。
如果集合不存在会自动创建集合。
@Test public void test1() { // _id存在时更新数据 mongoTemplate.save(new User(1, "aaa", "123456", 20)); // _id存在时抛出异常 mongoTemplate.insert(new User(2, "bbb", "113456", 21)); List<User> list = Arrays.asList( new User(3, "ccc", "124266", 22), new User(4, "ddd", "136521", 23), new User(5, "eee", "147258", 24)); // 批量插入 mongoTemplate.insert(list, User.class); }
通过 Spring Data MongoDB 还会给集合中多加一个 _class
的属性,存储新增时 Document 对应 Java 中类的全限定路径。
这么做为了查询时能把 Document 转换为 Java 类型。
3.3 查询文档
Query
类作为查询条件的容器,用于放置 Criteria 条件接口。Criteria
是标准查询的接口,可以引用静态的Criteria.where()
将字段和条件组合在一起进行查询。
@Test public void test1() { System.out.println("==========查询所有文档==========="); List<User> list = mongoTemplate.findAll(User.class); list.forEach(System.out::println); System.out.println("==========根据_id查询==========="); User user = mongoTemplate.findById(3, User.class); System.out.println(user); System.out.println("==========findOne返回第一个文档==========="); User one = mongoTemplate.findOne(new Query(), User.class); System.out.println(one); }
@Test public void test2() { System.out.println("==========条件查询==========="); // 查询name为"eee"的用户 Query query1 = new Query(Criteria.where("name").is("eee")); // 查询 age<23 的用户 Query query2 = new Query(Criteria.where("age").lt(23)); // 查询 21<=age<24 的用户 Query query3 = new Query(Criteria.where("age").gte(21).lt(24)); // 模糊查询 Query query4 = new Query(Criteria.where("password").regex("123")); System.out.println("==========多条件查询==========="); // 查询 age<24 且 密码包含"123" 的用户 Criteria criteria1 = new Criteria(); criteria1.andOperator(Criteria.where("age").lt(24), Criteria.where("password").regex("123")); Query query5 = new Query(criteria1); // 查询 age>23 或 密码包含"456" 的用户 Criteria criteria2 = new Criteria(); criteria2.orOperator(Criteria.where("age").gt(23), Criteria.where("password").regex("456")); Query query6 = new Query(criteria2); List<User> list = mongoTemplate.find(query6, User.class); list.forEach(System.out::println); }
@Test public void test3() { System.out.println("==========排序==========="); Query query1 = new Query(); query1.with(Sort.by(Sort.Order.desc("age"))); System.out.println("==========分页==========="); Query query2 = new Query(); query2.skip(0).limit(3); List<User> list = mongoTemplate.find(query2, User.class); list.forEach(System.out::println); }
使用 JSON 字符串方式查询:
@Test public void testFindByJson() { // 等值查询 Query query1 = new BasicQuery("{name:'eee'}"); // 多条件查询 Query query2 = new BasicQuery("{age:{$lt:24}, password:{$regex:'123'}}"); Query query3 = new BasicQuery("{$or:[{age:{$gt:23}}, {password:{$regex:'456'}}]}"); List<User> list = mongoTemplate.find(query3, User.class); list.forEach(System.out::println); }
3.4 修改文档
在 Mongodb 中无论是使用客户端 API 还是使用 Spring Data,更新返回结果一定是受行数影响。如果更新后的结果和更新前的结果是相同,返回 0。
updateFirst()
:只更新满足条件的第一条记录。updateMulti()
:更新所有满足条件的记录。upsert()
:没有符合条件的记录则插入数据。
@Test public void test1() { Query query = new Query(Criteria.where("name").is("eee")); Update update = new Update(); update.set("age", 25); // updateFirst() 只更新满足条件的第一条记录 UpdateResult updateResult = mongoTemplate.updateFirst(query, update, User.class); System.out.println("返回修改的记录数: " + updateResult.getModifiedCount()); }
@Test public void test2() { Query query = new Query(Criteria.where("age").gt(23)); Update update = new Update(); update.inc("age", 1); // updateMulti() 更新所有满足条件的记录 UpdateResult updateResult = mongoTemplate.updateMulti(query, update, User.class); System.out.println("返回修改的记录数: " + updateResult.getModifiedCount()); }
@Test public void test3() { // query查询结果不存在 Query query = new Query(Criteria.where("name").is("ggg")); Update update = new Update(); update.set("age", 28); update.setOnInsert("_id", 7); //不存在时插入 // upsert() 没有符合条件的记录则插入数据 UpdateResult updateResult = mongoTemplate.upsert(query, update, User.class); System.out.println("返回修改的记录数: " + updateResult.getModifiedCount()); }
3.5 删除文档
@Test public void testDelete() { //删除所有文档, 不如用dropCollection() //mongoTemplate.remove(new Query(),Employee.class); //条件删除 Query query = new Query(Criteria.where("name").is("fff")); mongoTemplate.remove(query, User.class); }
四、聚合操作
4.1 使用 Aggregation 实现
用 Aggregation 集合接收聚合操作,用 MongoTemplate 对象直接调用 aggregate,传入聚合操作集合、表名、映射对象。
@Test public void testAggregation() { // 1.先定义聚合操作 MatchOperation match = Aggregation.match(Criteria.where("type").is("novel")); SortOperation sort = Aggregation.sort(Sort.Direction.ASC, "favCount"); // 2.按顺序组合每一个聚合步骤 TypedAggregation<Book2> typedAggregation = Aggregation.newAggregation(Book2.class, match, sort); // 3.执行聚合操作, 可以使用 Document、Map、自定义实体类 接收结果 AggregationResults<Document> aggregate = mongoTemplate.aggregate(typedAggregation, Document.class); List<Document> results = aggregate.getMappedResults(); results.forEach(System.out::println); }
4.2 使用 Aggregates 实现
用 Aggregates 和 Bson 构建聚合操作对象,用预先生成的 MongoCollection 对象调用 aggregate 执行。
@Test public void testAggregates(){ // 1.先通过集合名拿到所有文档 MongoCollection<Document> collection = mongoTemplate.getCollection("book2"); // 2.Aggregates提供各种聚合操作符,返回一个Bson对象 Bson matchBson = Aggregates.match(new Document("type", "travel")); // Bson matchBson = Aggregates.match(Filters.eq("type", "travel"));//Filters来实现过滤 Bson sortBson = Aggregates.sort(Sorts.ascending("favCount")); // Bson sortBson = Aggregates.sort(new Document("favCount", 1)); // 3.构建一个List<Bson>, 并把每一个聚合操作按顺序加进去 List<Bson> bsonList = new ArrayList<>(); bsonList.add(matchBson); bsonList.add(sortBson); // 4.最后传入aggregate方法中执行,并且接收结果集 AggregateIterable<Document> resultList = collection.aggregate(bsonList); resultList.forEach(System.out::println); }
示例一:统计文档中的书籍总量、收藏总数、平均收藏量
@Test public void test1() { MongoCollection<Document> collection = mongoTemplate.getCollection("book2"); Bson groupBson = Aggregates.group(null, Accumulators.sum("bookCount", 1), Accumulators.sum("favCount", "$favCount"), Accumulators.avg("favAvg", "$favCount")); List<Bson> bsonList = new ArrayList<>(); bsonList.add(groupBson); AggregateIterable<Document> resultList = collection.aggregate(bsonList); resultList.forEach(System.out::println); }
示例二:统计tag标签的热度排行 (根据favCount总量排行即为热度)
@Test public void test4() { MongoCollection<Document> collection = mongoTemplate.getCollection("book2"); Bson unwindBson = Aggregates.unwind("$tag"); Bson groupBson = Aggregates.group("$tag", Accumulators.sum("favCount", "$favCount")); Bson sortBson = Aggregates.sort(new Document("favCount", -1)); List<Bson> bsonList = new ArrayList<>(); bsonList.add(unwindBson); bsonList.add(groupBson); bsonList.add(sortBson); AggregateIterable<Document> resultList = collection.aggregate(bsonList); resultList.forEach(System.out::println); }
4.3 应用案例
示例一:统计每个作者的每本book的收藏数
@Test public void test1() { GroupOperation group = Aggregation .group("$author.name", "$title") .sum("$favCount").as("favCount"); TypedAggregation<Book2> typedAggregation = Aggregation.newAggregation(Book2.class, group); AggregationResults<Document> aggregate = mongoTemplate.aggregate(typedAggregation, Document.class); List<Document> mappedResults = aggregate.getMappedResults(); mappedResults.forEach(System.out::println); }
示例二:每个作者的book的tag合集
@Test public void test2() { UnwindOperation unwind = Aggregation.unwind("$tag"); GroupOperation group = Aggregation .group("$author.name") .addToSet("$type").as("types"); TypedAggregation<Book2> typedAggregation = Aggregation.newAggregation(Book2.class, unwind, group); AggregationResults<Document> aggregate = mongoTemplate.aggregate(typedAggregation, Document.class); List<Document> mappedResults = aggregate.getMappedResults(); mappedResults.forEach(System.out::println); }
示例三:联表查询用户以及对应的订单信息
@Test public void test1() { LookupOperation lookup = Aggregation.lookup("order", "_id", "customerId", "order"); TypedAggregation<Customer> orderTypedAggregation = Aggregation.newAggregation(Customer.class, lookup); AggregationResults<Document> aggregate = mongoTemplate.aggregate(orderTypedAggregation, Document.class); List<Document> mappedResults = aggregate.getMappedResults(); mappedResults.forEach(System.out::println); }
示例四:联表查询订单信息以及对应的商品项
@Test public void test2() { LookupOperation lookup = Aggregation.lookup("orderItem", "_id", "orderId", "orderItem"); TypedAggregation<Order> orderItemTypedAggregation = Aggregation.newAggregation(Order.class, lookup); AggregationResults<Document> aggregate = mongoTemplate.aggregate(orderItemTypedAggregation, Document.class); List<Document> mappedResults = aggregate.getMappedResults(); mappedResults.forEach(System.out::println); }
总结
本文是对MongoDB的学习,SpringBoot整合MongoDB的SpringData,配置文件中如何连接,实体类如何映射到文档,如何通过API进行集合操作和文档的增删查改。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。