前言
??MongoDB 是一種流行的 NoSQL 數據庫,適合存儲大量的非結構化數據。MongoTemplate 是 Spring Data MongoDB 中的一個核心組件,它提供了一組豐富的 API 來與 MongoDB 進行交互。它封裝了許多常見的數據庫操作,使開發者能夠輕松執行 CRUD 操作、處理復雜查詢和聚合等。本文將詳細介紹 MongoTemplate 的基本用法,包含語法介紹和具體的使用示例。
一、初識 MongoTemplate
1.1 Spring Data MongoDB 簡介
??Spring Data MongoDB 是 Spring Data 項目的一部分,提供了與 MongoDB 文檔數據庫的集成。Spring Data MongoDB 的關鍵功能是一個以 POJO 為中心的模型,用于與 MongoDB 數據集合交互,并輕松地編寫一個存儲庫風格的數據訪問層。在 Spring Boot 項目中使用 MongoDB,首先需要引入 MongoDB 的依賴,通過在 POM 文件中引入 MongoDB 的依賴坐標,即可將操作 MongoDB 的類庫整合入 SpringBoot 項目當中,相關依賴如下:
<!-- springboot 整合 mongodb -->
<dependency> <groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId><version>x.y.z</version>
</dependency>
1.2 MongoTemplate 簡介
??MongoTemplate 類位于 org.springframework.data.mongodb.core 包中,是 Spring 支持 MongoDB 的高級抽象類,為與 MongoDB 數據庫交互提供了豐富的功能集。其封裝了 MongoClient,提供了一個更高層次的模板方法 API 來簡化 MongoDB 的操作。通過相對簡單的方法來執行創建、更新、刪除和查詢 MongoDB 等操作,同時集成了 Spring 的轉換和異常處理機制。使用 MongoTemplate,不需要關心低層次的數據庫連接和錯誤處理。而且 MongoTemplate 支持將 Java 對象映射到 MongoDB 文檔,并提供了一組方法,用于在 Java 對象和 MongoDB 文檔之間進行轉換,這樣可以方便地操作和管理數據。
【注意】MongoTemplate 是線程安全的,一旦配置好就可以在多個實例中重復使用(多線程環境中)。
??我們先看看 MongoTemplate 的構造方法,它有幾個重載的構造函數,如下所示:
/*** 根據 MongoClient 對象和要對其進行操作的默認數據庫名稱去實例化 MongoTemplate。*/
public MongoTemplate(MongoClient mongoClient, String databaseName) {}
/*** 根據 MongoDatabaseFactory 對象實例化 MongoTemplate,^ MongoDatabaseFactory 封裝了 MongoClient 對象、數據庫名稱、用戶名和密碼等信息。*/
public MongoTemplate(MongoDatabaseFactory mongoDbFactory) {}
/*** 用于對象和文檔映射的 MongoConverter 接口實現去實例化 MongoTemplate*/
public MongoTemplate(MongoDatabaseFactory mongoDbFactory, MongoConverter mongoConverter) {
}
1.3 添加配置
??引入依賴之后,需要在配置文件中添加 MongoDB 的連接信息,如同使用 MySQL 一樣需要給出它的連接信息。可以通過配置文件,定義其配置參數,具體參數有如下(將其對應參數寫在 application.properties 或者 application.yml 即可):
參數 | 描述 |
---|---|
spring.data.mongodb.additional-hosts | 驗證的數據庫 |
spring.data.mongodb.authentication-database | 驗證的數據庫 |
spring.data.mongodb.auto-index-creation | 是否自動創建索引 |
spring.data.mongodb.database | 指定要使用的數據庫名稱,初始化數據的時候,會自動創建。 |
spring.data.mongodb.field-naming-strategy | 字段命名策略 |
spring.data.mongodb.gridfs.bucket | |
spring.data.mongodb.gridfs.database | |
spring.data.mongodb.host | 設置 MongoDB 主機名,默認為 localhost。 |
spring.data.mongodb.password | MongoDB數據庫密碼,根據實際情況填寫即可 |
spring.data.mongodb.port | 設置 MongoDB 端口號,默認為 27017。 |
spring.data.mongodb.repositories.type | |
spring.data.mongodb.ssl.bundle | |
spring.data.mongodb.ssl.enabled | |
spring.data.mongodb.uri | 定義完整的 MongoDB URI 地址,通常優先于其他單獨的屬性 |
spring.data.mongodb.username | MongoDB數據庫用戶,根據實際情況填寫即可 |
spring.data.mongodb.uuid-representation |
1.4 定義對應集合的實體類
??操作 MySQL 時,我們會將 MySQL 的表在項目中定義一個對應的實體類,操作 MongoDB 的集合也需要定義一個對應的實體類,這里定義一個 SysUser 的實體類來進行操作。
@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class SysUser {@Idprivate String id;@Field("name")private String name;private Integer age;private String gender;
}
注解名稱 | 作用對象 | 功能 |
---|---|---|
@Document | 實體類 | 表明這是一個 MongoDB 的文檔集合,相當于 MySQL 的數據表,默認為實體類名稱。 |
@CompoundIndex | 實體類 | 復合索引 |
@Id | 字段 | 用于實體類中的成員變量,表示主鍵標識,會將該字段與 MongoDB 生成的 _id 字段進行對應。 |
@Field | 字段 | 用于實體類中的成員變量,表示 MongoDB 文檔集合中的字段,其值對應集合的字段名稱。 |
@Indexed | 字段 | 聲明該字段需要加索引,加索引后以該字段為條件檢索將大大提高速度 |
@Transient | 字段 | 表示該字段不在 mongo 中存儲,既忽略該字段 |
【注意】就個人而言,不太推薦使用 @Document 來定義實體類,由于 Mongo 的特性,在我們保存數據時,若是集合中沒有某些字段,Mongo 會自動創建,而且處于業務需求,可能存在同樣的數據結構、不同內容需要存放于不同的集合中,我們只需創建一個實體類,然后指定不同集合存儲數據即可。
1.5 注入 MongoTemplate
??MongoTemplate 基于 Spring 容器提供了一組對 MongoDB 操作的基本方法,只要將 MongoTemplate 注入到需要使用的類中,即可直接使用。通過 @Autowired 將 MongoTemplate 進行注入,如下所示:
@Resource
private MongoTemplate mongoTemplate;
二、核心對象
??MongoDB 支持非常強大的查詢功能,使用 Query 和 Criteria 對象,可以構建復雜的查詢條件并執行查詢。Criteria 是 MongoTemplate 的標準查詢接口,它可以把多個查詢條件通過鏈式操作進行拼接,然后通過 Query 可以構建查詢語句。
2.1 Query
??Query 表示條件、排序等的 MongoDB 查詢對象,用來封裝所有的查詢條件。我們先看看 Query 的構造方法,如下所示:
public Query() {
}/*** 通過注入一個 CriteriaDefinition 條件對象獲得 Query 查詢對象* 在簡單查詢時使用此方法將非常的方便*/
public Query(CriteriaDefinition criteriaDefinition) {this.addCriteria(criteriaDefinition);
}
??Query 對象創建也很簡單,如下所示:
// 用來封裝所有條件的對象
Query query = new Query();
// 或者
Query query = new Query(criteria);
??Query 類有一些額外的方法,可以為查詢提供選項:
方法 | 簡要說明 |
---|---|
Query addCriteria(CriteriaDefinition criteriaDefinition) | 用于向查詢添加其他查詢條件 |
Field fields() | 用于定義要包含在查詢結果中的字段 |
Query skip(long skip) | 跳過文檔的數量,可以與 limit 配合使用實現分頁效果。 |
Query limit(int limit) | 用于限制將返回文檔結果的數量(大小) |
Query with(Pageable pageable) | 添加一個分頁對象 |
Query with(Sort sort) | 用于為結果提供排序定義 |
@Test
public void complexQuery() {Query pageQuery=query.with(PageRequest.of(pageIndex - 1, pageSize)).with(Sort.by(Sort.Direction.DESC,"classNo"));// 根據單個條件查詢集合中的文檔數據,并按指定字段進行排序與限制指定數目Query query = new Query(Criteria.where("userName").is(userName)).with(Sort.by("createTime")).limit(2).skip(1);
}
2.2 Criteria
??用于封裝所有的查詢條件對象,相當于 SQL 的 where。它遵循流暢的 API 風格,可以輕松地將多個條件鏈接在一起。我們先看看 Criteria 的構造方法,如下所示:
public Criteria() {}public Criteria(String key) {}protected Criteria(List<Criteria> criteriaChain, String key) {}
??Criteria 類提供以下方法,所有這些方法都對應于 MongoDB 中的操作符:
方法 | Mongodb | 簡要說明 |
---|---|---|
Criteria where(string key) | $expr | 靜態方法,用它可以很方便的定義查詢條件 |
Criteria and(String key) | $and | |
Criteria all(Object value) | 匹配所有指定元素的文檔。 | |
Criteria exists(boolean value) | $exists | 查詢存在指定字段的文檔。 |
Criteria gt(Object value) | $gt | 范圍查詢,匹配大于(>)指定值的文檔 |
Criteria gte(Object value) | $gte | 范圍查詢,匹配大于等于(>=)指定值的文檔。 |
Criteria in(Object… values) | $in | 包含 |
Criteria is(Object value) | $is | 精確查詢 |
Criteria isNull() | ||
Criteria isNullValue() | ||
Criteria lt(Object value) | $lt | 范圍查詢,匹配小于(<)指定值的文檔。 |
Criteria lte(Object value) | $lte | 范圍查詢,匹配小于等于(<=)指定值的文檔。 |
Criteria mod(Number value, Number remainder) | 取余條件查詢。 | |
Criteria ne(Object value) | $ne | 匹配不等于(≠)指定值的文檔。 |
Criteria nin(Object… values) | $nin | |
Criteria not(Object value) | $not | 查詢與表達式不匹配的文檔。 |
regex(String re) | $regex | 模糊條件。正則表達式,用于模式匹配 |
Criteria size(int size) | $size | 匹配數組長度為指定大小的文檔。 |
Criteria andOperator(Criteria… criteria) | $and | 創建與操作 |
Criteria orOperator(Criteria… criteria) | $or | 創建或操作 |
Criteria norOperator(Criteria… criteria) | $nor |
@Test
public void complexQuery() {/*** 根據【AND】關聯多個查詢條件,查詢集合中的文檔數據*/Criteria nameCriteria = Criteria.where("name").is("成龍");Criteria ageCriteria = Criteria.where("age").gte(30);Criteria orOperatorCriteria = new Criteria().orOperator(nameCriteria, ageCriteria);/*** 根據【OR】關聯多個查詢條件,查詢集合中的文檔數據*/Criteria genderCriteria = Criteria.where("gender").is("女");Criteria andOperatorCriteria = new Criteria().andOperator(genderCriteria);Query query = new Query();query.addCriteria(andOperatorCriteria);query.addCriteria(orOperatorCriteria);
}
??這里的寫法類似于 SQL 中的 where ( name = "成龍" or age >= 30 ) and gender=“女”
,總體來看,一個 Criteria 實例,就是一個查詢條件。我們可以通過 or、and 操作來不斷的組合生成一個新的Criteria實例,也就是一個新的查詢條件 ,并且可以以此查詢條件繼續組合生成更高級的Criteria,以此不斷的類推。
2.3 Update
??用于輕松構建 MongoDB 更新子句的類,位于 org.springframework.data.mongodb.core.query
包中。其常用方法如下表所示:
方法 | 簡要說明 |
---|---|
Update update(String key,Object value) | 更新字段 |
Update addToSet(String key) | 用來添加值到一個數組中去,如果數組中已經存在該值,那么將不會有任何的操作。 |
Update currentDate(String key) | 用來設置字段的值為當前時間 |
Update currentTimestamp(String key) | |
void inc(String key) | |
Update inc(String key, Number inc) | 用來對字段的值進行增加和減少指定的值 |
Update max(String key, Object value) | 用來判斷字段的值是否比指定的值大,如果是,則將指定的值設置給字段。 |
Update min(String key, Object value) | 用來判斷字段的值是否比指定的值小,如果是,則將指定的值設置給字段。 |
Update multiply(String key, Number multiplier) | 用來對字段的值乘以一個數字 |
Update pop(String key, Position pos) | 用來從字段數組中的頭部和尾部刪除一個元素 |
Update pull(String key, @Nullable Object value) | 用來從字段數組值中刪除所有指定的值 |
Update pullAll(String key, Object[] values) | 用來從字段數組值中刪除所有指定的值 |
Update push(String key, Object value) | 用來向已有的數組末尾加入一個元素。 要是不存在,就會創建一個新的。如果已存在,會造成元素的重復。所以在使用的時候,要確保該元素不存在。 |
Update rename(String oldName, String newName) | 用來對字段進行重命名 |
Update set(String key, Object value) | 將字段的值設置為指定的值,如果該字段不存在,將添加一個具有指定值的新字段。 |
Update setOnInsert(String key, Object value) | 設置字段值,字段不存在則新建字段 |
Update unset(String key) | 用來刪除指定的字段。 |
三、集合操作
??集合是 MongoDB 中存儲文檔的容器,類似于關系型數據庫中的表。它是數據庫中的一個邏輯分組,用于組織和管理相關的文檔。一個數據庫可以包含多個集合,每個集合可以包含零個或多個文檔。集合中的文檔可以具有不同的結構,即它們可以包含不同的字段和數據類型,這給 MongoDB 帶來了極大的靈活性,但都遵循 MongoDB 的文檔格式規范(BSON格式)。
3.1 新增操作
??在 MongoDB 中,集合是不需要手動創建,當創建文檔時,如果文檔所在的集合不存在,就會自動創建集合。MongoDB 會在第一次插入文檔時自動創建集合,但也可以顯式創建集合,以便進行自定義配置,如下所示:
MongoCollection<Document> createCollection(Class entityClass);
MongoCollection<Document> createCollection(Class entityClass, CollectionOptions collectionOptions);
MongoCollection<Document> createCollection(String collectionName);
MongoCollection<Document> createCollection(String collectionName CollectionOptions collectionOptions);
??CollectionOptions 指定了創建集合要用的一些參數:
public class CollectionOptions {// 指定集合中的最大文檔數量。當達到最大值,會自動刪除最早存入的文檔。private Long maxDocuments;// 指定整個集合的容量。當達到最大值,會將舊文檔移除。private Long size;// 是否創建固定大小集合。當達到最大值時,會自動覆蓋最早的文檔。當該值為 true 時,必須指定 size 參數。private Boolean capped;// 用于文檔驗證的表達式private Collation collation;// 用來設置自定義規則,對集合中的文檔進行驗證。private ValidationOptions validationOptions;// 用來創建時序集合的private TimeSeriesOptions timeSeriesOptions;
}
【注意】在 MongoDB 中,自動創建集合簡單快速、適合快速原型開發,不需要事先定義集合結構。但可能會導致數據結構不一致(尤其在團隊協作中),而且自動創建的集合無法預設索引或其他選項。特別說明一下,若插入的集合已經存在,則會拋出異常。
3.2 查詢操作
方法 | 簡要說明 |
---|---|
String getCollectionName(entityClass) | 可獲取到entityClass實體類所對應的集合名稱 |
MongoCollection<Document> getCollection(collectionName) | 返回的是基本的Driver集合對象,即DBCollection類型 |
Set<String> getCollectionNames() | 返回一個String列表,包含所有集合名稱 |
boolean collectionExists(entityClass) boolean collectionExists(String collectionName) | 判斷集合存在 |
3.3 刪除操作
??刪除集合是另一項常見的操作,MongoDB 提供了簡單的命令來執行此操作。刪除集合將刪除集合中的所有文檔,并釋放相關資源。
方法 | 簡要說明 |
---|---|
dropCollection(entityClass) | 刪除集合 |
dropCollection(collectionName) |
【注意】一旦集合被刪除,所有文檔將無法恢復。務必謹慎操作,尤其是在生產環境中,確保有足夠的權限進行集合的創建和刪除操作。通常,只有管理員用戶或具有特定權限的用戶才能執行這些操作。
四、文檔的 CRUD 操作
??文檔是 MongoDB 中的最小數據單元,以鍵值對的形式組織,類似于 JSON 對象(實際上是 BSON,即 Binary JSON)。MongoTemplate 提供了一系列方便的方法來執行基本的 CRUD 操作。CRUD 是 MongoDB 中的核心操作,包含插入、讀取、更新和刪除等,以下將逐一講解這些操作。
4.1 保存(插入)操作
??MongoTemplate 上有幾個便捷方法,如下表所示,用于保存和插入對象。Mongodb 中也像傳統的關系數據庫里表一樣,有主鍵(_id)概念,用來唯一標識。當用戶往 Mongodb 中插入一條新記錄的時候,如果沒有指定_id屬性,那么 mongodb 會自動生成一個 ObjectId 類型的值,保存為 _id 的值。
方法 | 簡要說明 |
---|---|
insert(T objectToSave) insert(T objectToSave, String collectionName) | |
insert(Class domainType) insert(Collection batchToSave, Class entityClass) insert(Collection batchToSave, String collectionName) | 文檔插入。 若新增數據的主鍵已經存在,則會拋出異常提示主鍵重復,不保存當前數據。 |
insertAll(Collection batchToSave) | 批量插入多個文檔,批量插入不用遍歷,效率高 |
save(T objectToSave) save(T objectToSave, String collectionName) | 用于保存或更新操作,傳遞定義好的JavaBean即可,被保存的數據對象會作為返回值被返回。 通過主鍵 ID 進行判斷,如果存在就更新,否則就插入。 |
【注意】沒指定集合名稱時,會取 @Document注解中的集合名稱。
@SpringBootTest
public class SaveTest {@Resourceprivate MongoTemplate mongoTemplate;private final String collectionName = "SaveTest";@BeforeEachpublic void init() {// 刪除集合mongoTemplate.dropCollection(collectionName);}/*** 自定義集合,插入文檔*/@Testpublic void insertTest() {SysUser sysUser = new SysUser("12", "黃小飛", "女", 33);mongoTemplate.insert(sysUser, collectionName);}/*** 自定義集合,批量插入文檔*/@Testpublic void insertBatchTest() {List<SysUser> userList = new ArrayList<>();userList.add(new SysUser("1", "白鹿", "女", 31));userList.add(new SysUser("2", "陳都靈", "女", 32));userList.add(new SysUser("3", "高圓圓", "女", 46));userList.add(new SysUser("4", "張含韻", "女", 36));userList.add(new SysUser("5", "李沁", "女", 35));userList.add(new SysUser("6", "胡歌", "男", 43));userList.add(new SysUser("7", "劉亦菲", "女", 38));userList.add(new SysUser("8", "成龍", "男", 71));userList.add(new SysUser("9", "楊冪", "男", 39));userList.add(new SysUser("10", "陳鈺琪", "女", 33));mongoTemplate.insert(userList, collectionName);}/*** 自定義集合,存儲文檔,如果沒有插入,否則更*/@Testpublic void saveTest() {SysUser sysUser = new SysUser("12", "黃小飛", "女", 33);mongoTemplate.save(sysUser, collectionName);}
}
【注意】使用 insert 插入文檔時,如果插入數據的主鍵已經存在,則會拋鍵重復異常,不保存當前數據。而使用 save 插入文檔時,如果插入數據的主鍵已經存在,則會更新當前數據,如果不存在則會保存當前數據。
4.2 查詢操作
??MongoDB 提供了靈活的查詢語法,支持條件查詢、復雜查詢、聚合查詢等。
方法 | 簡要說明 |
---|---|
List find(query, entityClass) List find(query, entityClass, collectionName) | 根據查詢條件查詢多個文檔 |
findOne(query, entityClass) findOne(query, entityClass, collectionName) | 用于查找集合中的單個文檔。如果找到多個匹配的文檔,它只返回第一個。 |
findById(id, entityClass) findById(id, entityClass, collectionName) | 根據ID查詢文檔。在添加數據時, MongoDB 會自動生成了 id,名為 _id 。 |
List findAll(className) List findAll(className, collectionName) | 查詢指定集合中所有數據 |
count(query, entityClass) count(query, collectionName) count(query, entityClass, collectionName) | 查詢符合條件的數量 |
findDistinct(query, field, entityClass, resultClass) findDistinct(query, field, collectionName, entityClass, resultClass) | 只能用于單個字段去重查詢的方法,主要用于獲取某個字段的所有不同值。 |
【注意】沒指定集合名稱時,會取 @Document注解中的集合名稱。
@SpringBootTest
public class FindTest {@Resourceprivate MongoTemplate mongoTemplate;private final String collectionName = "FindTest";@BeforeEachpublic void init() {// 刪除集合mongoTemplate.dropCollection(collectionName);List<SysUser> userList = new ArrayList<>();userList.add(new SysUser("1", "白鹿", "女", 31));userList.add(new SysUser("2", "陳都靈", "女", 32));userList.add(new SysUser("3", "高圓圓", "女", 46));userList.add(new SysUser("4", "張含韻", "女", 36));userList.add(new SysUser("5", "李沁", "女", 35));userList.add(new SysUser("6", "胡歌", "男", 43));userList.add(new SysUser("7", "劉亦菲", "女", 38));userList.add(new SysUser("8", "成龍", "男", 71));userList.add(new SysUser("9", "楊冪", "男", 39));userList.add(new SysUser("10", "陳鈺琪", "女", 33));mongoTemplate.insert(userList, collectionName);}/*** 根據條件查詢集合中符合條件的文檔*/@Testpublic void findTest() {Query query = new Query(Criteria.where("age").gte(30).lte(40));mongoTemplate.find(query, SysUser.class, collectionName).forEach(System.out::println);}/*** 根據條件查詢集合中符合條件的文檔,返回第一條數據*/@Testpublic void findOneTest() {Query query = new Query(Criteria.where("gender").is("女"));SysUser sysUser = mongoTemplate.findOne(query, SysUser.class, collectionName);System.out.println("查詢結果:" + sysUser);}/*** 查詢集合中指定的ID文檔數據*/@Testpublic void findByIdTest() {SysUser sysUser = mongoTemplate.findById("1", SysUser.class, collectionName);System.out.println(sysUser);}/*** 查詢集合中的全部文檔數據*/@Testpublic void findAllTest() {mongoTemplate.findAll(SysUser.class, collectionName).forEach(System.out::println);}@Testpublic void countTest() {System.out.println( mongoTemplate.count(new Query(), collectionName));}
}
4.3 更新操作
4.3.1 基本更新操作
??在 MongoDB 中,更新文檔的操作包括單文檔更新和多文檔更新,可以使用多種方法實現,常用的方法如下表所示。
方法 | 簡要說明 |
---|---|
UpdateResult updateFirst(query, update, entityClass) UpdateResult updateFirst(query, update, collectionName) UpdateResult updateFirst(query, update, entityClass, collectionName) | 用于更新第一個匹配查詢條件的文檔 |
UpdateResult updateMulti(query, update, entityClass) UpdateResult updateMulti(query, update, collectionName) UpdateResult updateMulti(query, update, entityClass, collectionName) | 用于更新所有匹配查詢條件的文檔 |
UpdateResult upsert(query, update, entityClass) UpdateResult upsert(query, update, collectionName) UpdateResult upsert(query, update, entityClass, collectionName) | 進行插入或更新操作。如果文檔不存在,則插入新文檔,否則更新文檔。 這種操作非常符合我們某些需要保證在一定條件下只能有一個文檔的情況。 |
【注意】沒指定集合名稱時,會取 @Document注解中的集合名稱。
@SpringBootTest
public class UpdateTest {@Resourceprivate MongoTemplate mongoTemplate;private final String collectionName = "UpdateTest";@BeforeEachvoid init() {mongoTemplate.dropCollection(collectionName);List<SysUser> sysUserList = new ArrayList<>();sysUserList.add(SysUser.builder().id("ID10001").name("Tom").age(34).gender("男").build());sysUserList.add(SysUser.builder().id("ID10002").name("Tony").age(23).gender("男").build());sysUserList.add(SysUser.builder().id("ID10003").name("Ross").age(44).gender("女").build());sysUserList.add(SysUser.builder().id("ID10004").name("Gloria").age(14).gender("女").build());sysUserList.add(SysUser.builder().id("ID10005").name("Linda").age(24).gender("女").build());sysUserList.add(SysUser.builder().id("ID10006").name("regina").age(26).gender("女").build());sysUserList.add(SysUser.builder().id("ID10007").name("John").age(22).gender("男").build());sysUserList.add(SysUser.builder().id("ID10008").name("Michael").age(22).gender("男").build());mongoTemplate.save(sysUserList, collectionName);}/*** 更新文檔,匹配查詢到的文檔數據中的第一條數據*/@Testpublic void updateFirstTest() {// 更新條件Query query = new Query(Criteria.where("_id").is("ID10001"));System.out.println("更新前" + mongoTemplate.find(query, SysUser.class,collectionName));Update update = new Update();// 更新值update.set("name", "張三");update.set("sex", "男");// 更新查詢滿足條件的文檔數據(第一條)UpdateResult updateResult = mongoTemplate.updateFirst(query, update, SysUser.class, collectionName);System.out.println(updateResult);}/*** 更新文檔,匹配查詢到的文檔數據中的所有數據*/@Testpublic void updateMultiTest() {// 更新條件Query query = new Query(Criteria.where("age").gte(30));// 更新值Update update = Update.update("age", 33);// 更新查詢滿足條件的文檔數據(全部)mongoTemplate.updateMulti(query, update, SysUser.class, collectionName);}@Testpublic void upsertTest() {Query query = new Query(Criteria.where("age").gte(60));Update update = Update.update("age", -1);mongoTemplate.upsert(query, update, SysUser.class, collectionName);}
}
4.3.2 查找并更新
??修改數據時首先對數據進行查詢,然后設置需要修改的值,進行數據的更新,如下表所示,可以選擇返回更新前或更新后的文檔。
方法 | 簡要說明 |
---|---|
findAndModify(query, update, entityClass) findAndModify(query, update, collectionName) | 更新相匹配的文檔,并返回舊的的文檔。 |
findAndModify(query, update, options, entityClass); findAndModify(query, update, options, entityClass, collectionName); | 更新相匹配的文檔,并返回舊的或新更新的文檔。 |
【注意】沒指定集合名稱時,會取 @Document注解中的集合名稱。
@SpringBootTest
public class UpdateTest {@Resourceprivate MongoTemplate mongoTemplate;private final String collectionName = "UpdateTest";@BeforeEachvoid init() {mongoTemplate.dropCollection(collectionName);List<SysUser> sysUserList = new ArrayList<>();sysUserList.add(SysUser.builder().id("ID10001").name("Tom").age(34).gender("男").build());sysUserList.add(SysUser.builder().id("ID10002").name("Tony").age(23).gender("男").build());sysUserList.add(SysUser.builder().id("ID10003").name("Ross").age(44).gender("女").build());sysUserList.add(SysUser.builder().id("ID10004").name("Gloria").age(14).gender("女").build());sysUserList.add(SysUser.builder().id("ID10005").name("Linda").age(24).gender("女").build());sysUserList.add(SysUser.builder().id("ID10006").name("regina").age(26).gender("女").build());sysUserList.add(SysUser.builder().id("ID10007").name("John").age(22).gender("男").build());sysUserList.add(SysUser.builder().id("ID10008").name("Michael").age(22).gender("男").build());mongoTemplate.save(sysUserList, collectionName);}@Testpublic void findAndModifyTest() {Query query = new Query(Criteria.where("_id").is("ID10001"));Update update = Update.update("name", "張三");mongoTemplate.findAndModify(query, update, SysUser.class, collectionName);}
}
4.4 刪除操作
基本刪除操作
??刪除操作同樣通過 Query 類構造要刪除的條件,然后調用 remove 方法進行刪除即可。
方法 | 簡要說明 |
---|---|
DeleteResult remove(Object object) DeleteResult remove(Object object, String collectionName) | 用于刪除數據,一般都是傳遞一個主鍵ID即可。 |
DeleteResult remove(query, entityClass) DeleteResult remove(query, collectionName) DeleteResult remove(query, entityClass, collectionName) | 用于刪除符合條件的文檔 |
【注意】沒指定集合名稱時,會取 @Document注解中的集合名稱。
@SpringBootTest
public class RemoveTest {@Resourceprivate MongoTemplate mongoTemplate;private final String collectionName = "RemoveTest";@BeforeEachpublic void init() {// 刪除集合mongoTemplate.dropCollection(collectionName);List<SysUser> userList = new ArrayList<>();userList.add(new SysUser("1", "白鹿", "女", 31));userList.add(new SysUser("2", "陳都靈", "女", 32));userList.add(new SysUser("3", "高圓圓", "女", 46));userList.add(new SysUser("4", "張含韻", "女", 36));userList.add(new SysUser("5", "李沁", "女", 35));userList.add(new SysUser("6", "胡歌", "男", 43));userList.add(new SysUser("7", "劉亦菲", "女", 38));userList.add(new SysUser("8", "成龍", "男", 71));userList.add(new SysUser("9", "楊冪", "男", 39));userList.add(new SysUser("10", "陳鈺琪", "女", 33));mongoTemplate.insert(userList, collectionName);}@Testpublic void removeOne() {Query query = new Query(Criteria.where("id").is("1"));SysUser sysUser = mongoTemplate.findOne(query, SysUser.class, collectionName);if (null != sysUser) {mongoTemplate.remove(sysUser, collectionName);}long count = mongoTemplate.count(query, collectionName);System.out.println("count = " + count);}@Testpublic void removeAll() {Query query = new Query(Criteria.where("age").gte(30));long count = mongoTemplate.count(query, collectionName);System.out.println("刪除前,count=" + count);// 刪除所有匹配的文檔mongoTemplate.remove(query, collectionName);count = mongoTemplate.count(query, collectionName);System.out.println("刪除后,count=" + count);}@Testpublic void removeLimit() {Query query = new Query(Criteria.where("age").gte(30));long count = mongoTemplate.count(query, collectionName);System.out.println("刪除前,count=" + count);// 刪除前兩個文檔mongoTemplate.remove(query.limit(2), collectionName);count = mongoTemplate.count(query, collectionName);System.out.println("刪除后,count=" + count);}
}
查找并刪除
方法 | 簡要說明 |
---|---|
findAndRemove(query, entityClass) findAndRemove(query, collectionName) | 用于查找并刪除單個文檔,并可以選擇返回刪除的文檔。如果找不到匹配的文檔,則返回 null。 |
findAllAndRemove(query, collectionName) findAllAndRemove(query, entityClass) findAllAndRemove(query, entityClass, collectionName) | 查詢出符合條件的所有結果,并將符合條件的所有數據刪除。 |
【注意】沒指定集合名稱時,會取 @Document注解中的集合名稱。
@SpringBootTest
public class RemoveTest {@Resourceprivate MongoTemplate mongoTemplate;private final String collectionName = "RemoveTest";@BeforeEachpublic void init() {// 刪除集合mongoTemplate.dropCollection(collectionName);List<SysUser> userList = new ArrayList<>();userList.add(new SysUser("1", "白鹿", "女", 31));userList.add(new SysUser("2", "陳都靈", "女", 32));userList.add(new SysUser("3", "高圓圓", "女", 46));userList.add(new SysUser("4", "張含韻", "女", 36));userList.add(new SysUser("5", "李沁", "女", 35));userList.add(new SysUser("6", "胡歌", "男", 43));userList.add(new SysUser("7", "劉亦菲", "女", 38));userList.add(new SysUser("8", "成龍", "男", 71));userList.add(new SysUser("9", "楊冪", "男", 39));userList.add(new SysUser("10", "陳鈺琪", "女", 33));mongoTemplate.insert(userList, collectionName);}/*** 刪除符合條件的單個文檔,并返回刪除的文檔*/@Testpublic void findAndRemoveTest() {Query query = new Query(Criteria.where("id").is(2));SysUser sysUser = mongoTemplate.findAndRemove(query, SysUser.class);System.out.println("刪除的文檔數據:" + sysUser.toString());}/*** 刪除符合條件的所有文檔,并返回刪除的文檔*/@Testpublic void findAllAndRemoveTest() {Query query = new Query(Criteria.where("age").gte(30));long count = mongoTemplate.count(query, collectionName);System.out.println("刪除前,count=" + count);// 刪除所有匹配的文檔List<SysUser> sysUserList = mongoTemplate.findAllAndRemove(query, collectionName);System.out.println("刪除的數據:" + Arrays.toString(sysUserList.toArray()));count = mongoTemplate.count(query, collectionName);System.out.println("刪除后,count=" + count);}@Testpublic void findAllAndRemoveLimit() {Query query = new Query(Criteria.where("age").gte(30));long count = mongoTemplate.count(query, collectionName);System.out.println("刪除前,count=" + count);// 刪除前兩個文檔List<SysUser> sysUserList = mongoTemplate.findAllAndRemove(query.limit(2), collectionName);System.out.println("刪除的數據:" + Arrays.toString(sysUserList.toArray()));count = mongoTemplate.count(query, collectionName);System.out.println("刪除后,count=" + count);}
}
五、知識拓展
5.1 查詢指定字段的值
??在 MongoDB 中,文檔是以鍵值對的形式存儲的,每個文檔可以包含多個字段,每個字段由一個鍵和一個值組成。在查詢文檔時,有時只需要獲取文檔中的部分字段,而不是全部字段,MongoTemplate 提供了一種簡單的方式來查詢指定字段的值。
-
查詢單個字段的值:要查詢單個字段的值,可以使用
findOne
方法,以下是查詢單個字段的值的示例代碼:Query query = new Query(); query.addCriteria(Criteria.where("name").is("John")); String fieldValue = mongoTemplate.findOne(query, String.class, "users"); System.out.println(fieldValue);
??在上面的示例中,創建了一個 Query 對象,并通過 Criteria 來指定查詢條件。然后調用 findOne 方法傳入查詢條件、返回值類型和集合名,它會返回符合條件的第一個文檔,并將指定字段的值轉換為指定的返回值類型。
-
查詢指定字段的值:要查詢指定字段的值,可以使用
fields
方法來指定要返回的字段,以下是查詢指定字段的值的示例代碼:Query query = new Query(); query.addCriteria(Criteria.where("age").gte(18)); query.fields().include("name").exclude("age"); List<User> users = mongoTemplate.find(query, User.class, "users"); for (User user : users) {System.out.println(user.getName()); }
??在上面的示例中,使用 fields 方法來指定要返回的字段。在 include 方法中,指定要返回的字段名。在 exclude 方法中,指定要排除的字段名。這樣,查詢結果中只會包含指定的字段。
5.2 結果類
DeleteResult
??此類包含有關已執行刪除操作的信息,如下表所示。
方法 | 簡要說明 |
---|---|
long getDeletedCount() | 返回已刪除的文檔數。 |
boolean wasAcknowledged() | 返回寫入是否已確認。 |
UpdateResult
??此類包含有關已執行更新或替換操作的信息,如下表所示。
方法 | 簡要說明 |
---|---|
long getMatchedCount() | 返回匹配的文檔數。 |
long getModifiedCount() | 返回已修改文檔的數量。 |
BsonValue getUpsertedId() | 如果執行的是一個upsert操作(即先嘗試更新,如果沒有找到匹配的文檔則插入),則返回新插入文檔的ID。 如果沒有進行upsert操作或者沒有插入任何文檔,則返回null。 |
boolean isModifiedCountAvailable() |
六、小結
??MongoDB 已經被越來越多的使用,它適合于對大量的、無固定數據結構的數據進行存儲,本文簡單的介紹了通過使用 MongoTemplate 來對 MongoDB 進行 CRUD 的操作。MongoTemplate 提供了一個靈活而強大的方式來操作 MongoDB 數據庫,非常適合在 Spring 應用中使用。我們可以根據自己的需求,進一步擴展和優化這些基礎操作。