文章目录
- 1. 准备工作
- 2. 在SpringBoot项目中集成MongoDB
- 2.1 引入依赖
- 2.2 编写配置文件
- 2.3 实体类
- 3. 测试
- 4. 文档操作
- 4.1 插入操作
- 4.1.1 单次插入
- 4.1.2 批量插入
- 4.2 查询操作
- 4.2.1 根据id查询
- 4.2.2 根据特定条件查询
- 4.2.3 正则查询
- 4.2.4 查询所有文档
- 4.2.5 排序后返回
- 4.3 删除操作
- 4.3.1 根据id删除
- 4.3.2 根据特定条件删除
- 4.4 修改操作
- 4.4.1 修改符合条件的第一条文档(updateFirst)
- 4.4.2 修改符合条件的所有文档(updateMulti)
- 5. 完整的测试代码
阅读本文前可以先阅读以下文章:
- MongoDB快速入门(MongoDB简介、MongoDB的应用场景、MongoDB中的基本概念、MongoDB的数据类型、MongoDB的安装与部署、MongoDB的常用命令)
- MongoDB的常用命令(数据库操作、集合操作、文档操作)
1. 准备工作
假设我们在做一个与自媒体相关的项目,项目引入了 MongoDB 存储与文章的评论数据
数据库名称为 article
,集合名称为 comment
,以下是可能用到的字段
字段名称 | 字段含义 | 字段类型 | 备注 |
---|---|---|---|
_id | ID | ObjectId或String | MongoDB文档的唯一标识符,作为主键使用 |
article_id | 文章ID | String | 文章的唯一标识符,用于关联评论和文章 |
content | 评论内容 | String | 用户发表的评论文本内容 |
user_id | 评论人ID | String | 发表评论的用户唯一标识符 |
nickname | 评论人昵称 | String | 发表评论的用户昵称,用于显示在评论列表中 |
create_time | 评论的日期时间 | Date | 评论创建的时间,格式通常为ISO日期时间格式 |
like_number | 点赞数 | Int32 | 评论获得的点赞数量,反映评论的受欢迎程度 |
reply_number | 回复数 | Int32 | 评论下方的回复数量,反映评论的互动程度 |
state | 状态 | String | 评论的可见状态,'0’表示评论不可见,'1’表示评论可见 |
parent_id | 上级ID | String | 评论的上级评论ID,如果为’0’或空,则表示该评论是顶级评论,没有上级评论 |
先创建一个名为 article 的数据库
use comment
接着运行以下 SQL,插入测试数据
/*Navicat Premium Data TransferSource Server : localhostSource Server Type : MongoDBSource Server Version : 80003 (8.0.3)Source Host : localhost:27017Source Schema : testTarget Server Type : MongoDBTarget Server Version : 80003 (8.0.3)File Encoding : 65001*/// ----------------------------
// Collection structure for comment
// ----------------------------
db.getCollection("comment").drop();
db.createCollection("comment");
db.getCollection("comment").createIndex({user_id: NumberInt("1")
}, {name: "user_id_1"
});// ----------------------------
// Documents of comment
// ----------------------------
db.getCollection("comment").insertOne({_id: ObjectId("6728a523d9496fae23c4c2a9"),article_id: NumberInt("100000"),content: "今天天气真好,阳光明媚",user_id: "1001",nickname: "Rose",create_time: ISODate("2024-11-04T10:42:43.056Z"),like_number: NumberInt("10"),state: null
});db.getCollection("comment").insertOne({_id: "2",article_id: "100001",content: "我夏天空腹喝凉开水,冬天喝温开水",user_id: "1005",nickname: "伊人憔悴",create_time: ISODate("2019-08-05T23:58:51.485Z"),like_number: NumberInt("2422"),state: "1"
});db.getCollection("comment").insertOne({_id: "3",article_id: "100001",content: "我一直喝凉开水,冬天夏天都喝。",user_id: "1004",nickname: "杰克船长",create_time: ISODate("2019-08-06T01:05:06.321Z"),like_number: NumberInt("667"),state: "1"
});db.getCollection("comment").insertOne({_id: "4",article_id: "100001",content: "专家说不能空腹吃饭,影响健康。",user_id: "1003",nickname: "凯撒大帝",create_time: ISODate("2019-08-06T08:18:35.288Z"),like_number: NumberInt("2000"),state: "1"
});db.getCollection("comment").insertOne({_id: "5",article_id: "100001",content: "研究表明,刚烧开的水千万不能喝,因为烫嘴。",user_id: "1003",nickname: "凯撒大帝",create_time: ISODate("2019-08-06T11:01:02.521Z"),like_number: NumberInt("3000"),state: "1"
});
2. 在SpringBoot项目中集成MongoDB
本次演示使用的环境为:JDK 17.0.7 + SpringBoot 3.0.2
2.1 引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2.2 编写配置文件
application.yml
server:port: 11006spring:data:mongodb:database: articlehost: 127.0.0.1port: 27017
# username:
# password:
2.3 实体类
- 在Spring Data MongoDB中,
@Field
注解用于指定文档中字段的名称,这在字段名称与MongoDB集合中存储的字段名称不一致时非常有用- 如果实体类的字段名称与MongoDB文档中的字段名称相同,那么不需要使用
@Field
注解- 通过
@Document
注解指定集合名称
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;import java.util.Date;/*** Comment 实体类,用于映射MongoDB中的 comment 集合。*/
@Document(collection = "comment")
public class Comment {/*** MongoDB文档的唯一标识符,作为主键使用。*/@Idprivate String id;/*** 文章的唯一标识符,用于关联评论和文章。*/@Field("article_id")private String articleId;/*** 用户发表的评论文本内容。*/private String content;/*** 发表评论的用户唯一标识符。*/@Field("user_id")private String userId;/*** 发表评论的用户昵称,用于显示在评论列表中。*/private String nickname;/*** 评论创建的时间,格式通常为ISO日期时间格式。*/@Field("create_time")private Date createTime;/*** 评论获得的点赞数量,反映评论的受欢迎程度。*/@Field("like_number")private Integer likeNumber;/*** 评论下方的回复数量,反映评论的互动程度。*/@Field("reply_number")private Integer replyNumber;/*** 评论的可见状态,'0’表示评论不可见,'1’表示评论可见。*/private String state;/*** 评论的上级评论ID,如果为’0’或空,则表示该评论是顶级评论,没有上级评论。*/@Field("parent_id")private String parentId;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getArticleId() {return articleId;}public void setArticleId(String articleId) {this.articleId = articleId;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public Integer getLikeNumber() {return likeNumber;}public void setLikeNumber(Integer likeNumber) {this.likeNumber = likeNumber;}public Integer getReplyNumber() {return replyNumber;}public void setReplyNumber(Integer replyNumber) {this.replyNumber = replyNumber;}public String getState() {return state;}public void setState(String state) {this.state = state;}public String getParentId() {return parentId;}public void setParentId(String parentId) {this.parentId = parentId;}@Overridepublic String toString() {return "Comment{" +"id='" + id + '\'' +", articleId='" + articleId + '\'' +", content='" + content + '\'' +", userId='" + userId + '\'' +", nickname='" + nickname + '\'' +", createTime=" + createTime +", likeNumber=" + likeNumber +", replyNumber=" + replyNumber +", state='" + state + '\'' +", parentId='" + parentId + '\'' +'}';}}
3. 测试
- 在 SpringBoot 中操作 MongoDB,可以使用
MongoRepository
对象,也可以使用MongoTemplate
对象MongoRepository
是基于 Spring Data 的 Repository 抽象,它提供了一套标准的数据访问方法,使得 CRUD 操作变得非常简单- 如果需要进行复杂的查询或需要细粒度的控制,
MongoTemplate
可能是更好的选择
我们编写一个测试类,在测试类中注入 MongoTemplate
对象(与使用 RedisTemplate
类似)
import com.mongodb.client.MongoDatabase;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;@SpringBootTest
class MongodbApplicationTests {@Autowiredprivate MongoTemplate mongoTemplate;@Testpublic void showCurrentDatabase() {MongoDatabase db = mongoTemplate.getDb();System.out.println("db.getName() = " + db.getName());}@Testpublic void showAllCollections() {mongoTemplate.getCollectionNames().forEach(System.out::println);}}
4. 文档操作
4.1 插入操作
4.1.1 单次插入
@Test
public void testInsert() {Comment comment = new Comment();comment.setArticleId("article123");comment.setContent("这是一个很好的文章!");comment.setUserId("1003");comment.setNickname("评论者A");comment.setCreateTime(new Date());comment.setLikeNumber(10);comment.setReplyNumber(2);comment.setState("1");comment.setParentId("0");mongoTemplate.insert(comment);// 拿到插入后的评论IDSystem.out.println("tempComment.getId() = " + comment.getId());
}
4.1.2 批量插入
@Test
public void testInsertAll() {List<Comment> commentList = new ArrayList<>();for (int i = 0; i < 5; i++) {Comment comment = new Comment();comment.setArticleId("article" + (i + 1));comment.setContent("这是第 " + (i + 1) + " 条评论内容");comment.setUserId(String.valueOf(1003));comment.setNickname("评论者" + (i + 1));comment.setCreateTime(new Date());comment.setLikeNumber(5 + i); // 假设点赞数从5开始递增comment.setReplyNumber(0); // 假设初始回复数为0comment.setState("1"); // 假设所有评论都是可见的comment.setParentId("0"); // 假设所有评论都是顶级评论commentList.add(comment);}// 批量插入评论mongoTemplate.insertAll(commentList);
}
4.2 查询操作
分页参数和跳过多少条文档需要通过
Query
对象指定
4.2.1 根据id查询
@Test
public void testFindById() {Comment comment = mongoTemplate.findById("2", Comment.class);System.out.println("comment = " + comment);
}
4.2.2 根据特定条件查询
@Test
public void testFindByUserIdAndCreateTime() {String userId = "1003";Query query = new Query();Criteria criteria = Criteria.where("user_id").is(userId).and("create_time").lte(new Date());query.addCriteria(criteria).skip(0).limit(5);List<Comment> commentList = mongoTemplate.find(query, Comment.class);commentList.forEach(System.out::println);
}
4.2.3 正则查询
@Test
public void testFindByRegex() {String keyword = "开水";Query query = new Query();Criteria criteria = Criteria.where("content").regex(keyword);query.addCriteria(criteria);List<Comment> commentList = mongoTemplate.find(query, Comment.class);commentList.forEach(System.out::println);
}
4.2.4 查询所有文档
@Test
public void testFindALl() {List<Comment> commentList = mongoTemplate.findAll(Comment.class);commentList.forEach(System.out::println);
}
4.2.5 排序后返回
@Test
public void testFindByArticleIdWithCreatedTimeAsc() {String articleId = "100001";Criteria criteria = Criteria.where("article_id").is(articleId).and("create_time").lte(new Date());Query query = new Query();query.addCriteria(criteria).with(Sort.by(Sort.Order.asc("create_time")));List<Comment> commentList = mongoTemplate.find(query, Comment.class);commentList.forEach(System.out::println);
}
4.3 删除操作
4.3.1 根据id删除
@Test
public void testDeleteById() {Criteria criteria = Criteria.where("_id").is("2");DeleteResult deleteResult = mongoTemplate.remove(new Query(criteria), Comment.class);System.out.println("deleteResult.getDeletedCount() = " + deleteResult.getDeletedCount());
}
4.3.2 根据特定条件删除
@Test
public void testDeleteByUserIdAndCreateTime() {String userId = "1003";Date date = new Date();// 删除两分钟以内发布的评论date.setTime(date.getTime() - 2 * 60 * 1000);Query query = new Query();Criteria criteria = Criteria.where("user_id").is(userId).and("create_time").gte(date).lte(new Date()).and("state").is("1");query.addCriteria(criteria);DeleteResult deleteResult = mongoTemplate.remove(query, Comment.class);System.out.println("deleteResult.getDeletedCount() = " + deleteResult.getDeletedCount());
}
4.4 修改操作
4.4.1 修改符合条件的第一条文档(updateFirst)
@Test
public void testUpdateFirst() {Comment comment = new Comment();comment.setId("6728a523d9496fae23c4c2a9");comment.setLikeNumber(102);Query query = new Query();query.addCriteria(Criteria.where("_id").is(comment.getId()));Update update = new Update();update.set("like_number", comment.getLikeNumber());UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Comment.class);System.out.println("updateResult.getMatchedCount() = " + updateResult.getMatchedCount());System.out.println("updateResult.getModifiedCount() = " + updateResult.getModifiedCount());
}
4.4.2 修改符合条件的所有文档(updateMulti)
@Test
public void testUpdateMulti() {Query query = new Query();Criteria criteria = Criteria.where("article_id").is("100001").and("state").is("1");query.addCriteria(criteria);Update update = new Update();update.set("nickname", "聂可以");UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Comment.class);System.out.println("updateResult.getMatchedCount() = " + updateResult.getMatchedCount());System.out.println("updateResult.getModifiedCount() = " + updateResult.getModifiedCount());
}
5. 完整的测试代码
import cn.edu.scau.pojo.Comment;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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 java.util.ArrayList;
import java.util.Date;
import java.util.List;@SpringBootTest
class MongodbApplicationTests {@Autowiredprivate MongoTemplate mongoTemplate;@Testpublic void showCurrentDatabase() {MongoDatabase db = mongoTemplate.getDb();System.out.println("db.getName() = " + db.getName());}@Testpublic void showAllCollections() {mongoTemplate.getCollectionNames().forEach(System.out::println);}@Testpublic void testInsert() {Comment comment = new Comment();comment.setArticleId("article123");comment.setContent("这是一个很好的文章!");comment.setUserId("1003");comment.setNickname("评论者A");comment.setCreateTime(new Date());comment.setLikeNumber(10);comment.setReplyNumber(2);comment.setState("1");comment.setParentId("0");mongoTemplate.insert(comment);// 拿到插入后的评论IDSystem.out.println("tempComment.getId() = " + comment.getId());}@Testpublic void testInsertAll() {List<Comment> commentList = new ArrayList<>();for (int i = 0; i < 5; i++) {Comment comment = new Comment();comment.setArticleId("article" + (i + 1));comment.setContent("这是第 " + (i + 1) + " 条评论内容");comment.setUserId(String.valueOf(1003));comment.setNickname("评论者" + (i + 1));comment.setCreateTime(new Date());comment.setLikeNumber(5 + i); // 假设点赞数从5开始递增comment.setReplyNumber(0); // 假设初始回复数为0comment.setState("1"); // 假设所有评论都是可见的comment.setParentId("0"); // 假设所有评论都是顶级评论commentList.add(comment);}// 批量插入评论mongoTemplate.insertAll(commentList);}@Testpublic void testFindById() {Comment comment = mongoTemplate.findById("2", Comment.class);System.out.println("comment = " + comment);}@Testpublic void testFindALl() {List<Comment> commentList = mongoTemplate.findAll(Comment.class);commentList.forEach(System.out::println);}@Testpublic void testFindByRegex() {String keyword = "开水";Query query = new Query();Criteria criteria = Criteria.where("content").regex(keyword);query.addCriteria(criteria);List<Comment> commentList = mongoTemplate.find(query, Comment.class);commentList.forEach(System.out::println);}@Testpublic void testFindByUserIdAndCreateTime() {String userId = "1003";Query query = new Query();Criteria criteria = Criteria.where("user_id").is(userId).and("create_time").lte(new Date());query.addCriteria(criteria).skip(0).limit(5);List<Comment> commentList = mongoTemplate.find(query, Comment.class);commentList.forEach(System.out::println);}@Testpublic void testFindByArticleIdWithCreatedTimeAsc() {String articleId = "100001";Criteria criteria = Criteria.where("article_id").is(articleId).and("create_time").lte(new Date());Query query = new Query();query.addCriteria(criteria).with(Sort.by(Sort.Order.asc("create_time")));List<Comment> commentList = mongoTemplate.find(query, Comment.class);commentList.forEach(System.out::println);}@Testpublic void testDeleteById() {Criteria criteria = Criteria.where("_id").is("672a88601f90870e2451905a");DeleteResult deleteResult = mongoTemplate.remove(new Query(criteria), Comment.class);System.out.println("deleteResult.getDeletedCount() = " + deleteResult.getDeletedCount());}@Testpublic void testDeleteByUserIdAndCreateTime() {String userId = "1003";Date date = new Date();// 删除两分钟以内发布的评论date.setTime(date.getTime() - 2 * 60 * 1000);Query query = new Query();Criteria criteria = Criteria.where("user_id").is(userId).and("create_time").gte(date).lte(new Date()).and("state").is("1");query.addCriteria(criteria);DeleteResult deleteResult = mongoTemplate.remove(query, Comment.class);System.out.println("deleteResult.getDeletedCount() = " + deleteResult.getDeletedCount());}@Testpublic void testUpdateFirst() {Comment comment = new Comment();comment.setId("6728a523d9496fae23c4c2a9");comment.setLikeNumber(102);Query query = new Query();query.addCriteria(Criteria.where("_id").is(comment.getId()));Update update = new Update();update.set("like_number", comment.getLikeNumber());UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Comment.class);System.out.println("updateResult.getMatchedCount() = " + updateResult.getMatchedCount());System.out.println("updateResult.getModifiedCount() = " + updateResult.getModifiedCount());}@Testpublic void testUpdateMulti() {Query query = new Query();Criteria criteria = Criteria.where("article_id").is("100001").and("state").is("1");query.addCriteria(criteria);Update update = new Update();update.set("nickname", "聂可以");UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Comment.class);System.out.println("updateResult.getMatchedCount() = " + updateResult.getMatchedCount());System.out.println("updateResult.getModifiedCount() = " + updateResult.getModifiedCount());}}