前置文章:
MongoDB-基礎使用(一),該文主要介紹MongoDB概念、安裝、庫/集合(表)/文檔(行)操作。
零、本文綱要
一、索引
- 索引類型
- 索引管理操作
- 索引使用
二、API操作-快速入門
- pom.xml
- application.yml
- 啟動類
- 測試
- 創建測試集合實體類
- 持久層接口&業務層編寫
- 測試
- 根據上級ID查詢分頁列表
- MongoTemplate
一、索引
MongoDB索引使用B樹數據結構(確切的說是B-Tree,MySQL是B+Tree)
注意:該部分的內容與Redis、JS類似,整體特性又與MySQL相近。可以簡單了解以下。
1. 索引類型
a、單字段索引
b、復合索引
c、地理空間索引
d、文本索引
e、哈希索引
2. 索引管理操作
① 索引查看
# 索引查看
db.collection.getIndexes()
#如:
db.collection_test.getIndexes()
> db.collection_test.getIndexes()
[
{
"v" : 2, #索引的版本號
"key" : { #索引的字段
"_id" : 1 #1代表升序
},
"name" : "_id_", #索引的名稱,默認為 "字段名_" + "升降序規則數字",如:"userid_1_nickname_-1"
"ns" : "db_test.collection_test" #命名空間,數據庫.集合
}
]
② 索引創建
# 創建單字段索引
db.collection.createIndex(keys, options)
#如:
db.collection_test.createIndex({userid: 1}) #此處1代表升序,-1則為降序,單字段索引升降序不影響整體查詢效率
# 創建復合索引
#如:
db.collection_test.createIndex({userid: 1, nickname: -1})
以下了解即可:
參數 | 類型 | 描述 |
---|---|---|
background | Boolean | 建索引過程會阻塞其它數據庫操作,background可指定以后臺方式創建索引,即增加 "background" 可選參數。 "background" 默認值為false。 |
unique | Boolean | 建立的索引是否唯一。指定為true創建唯一索引。默認值為false. |
name | string | 索引的名稱。如果未指定,MongoDB的通過連接索引的字段名和排序順序生成一個索引名稱。 |
dropDups | Boolean | 3.0+版本已廢棄。在建立唯一索引時是否刪除重復記錄,指定 true 創建唯一索引。默認值為 false. |
sparse | Boolean | 對文檔中不存在的字段數據不啟用索引;這個參數需要特別注意,如果設置為true的話,在索引字段中不會查詢出不包含對應字段的文檔.。默認值為 false. |
expireAfterSeconds | integer | 指定一個以秒為單位的數值,完成 TTL設定,設定集合的生存時間。 |
v | index version | 索引的版本號。默認的索引版本取決于mongod創建索引時運行的版本。 |
weights | document | 索引權重值,數值在 1 到 99,999 之間,表示該索引相對于其他索引字段的得分權重。 |
default_language | string | 對于文本索引,該參數決定了停用詞及詞干和詞器的規則的列表。 默認為英語 |
language_override | string | 對于文本索引,該參數指定了包含在文檔中的字段名,語言覆蓋默認的language,默認值為 language. |
③ 索引移除
# 索引移除
db.collection.dropIndex(index)
#如:
db.collection_test.dropIndex("userid_1")
db.collection_test.dropIndex({userid: 1})
# 移除所有索引(默認"_id_"索引不會被移除)
db.collection_test.dropIndexes()
3. 索引使用
① 執行計劃
# 執行計劃
db.collection.find(query,options).explain(options)
#如:
db.collection_test.find({userid: "1003"}).explain()
"stage" : "COLLSCAN", 表示全集合掃描
"stage" : "IXSCAN" ,基于索引的掃描
② 涵蓋查詢(索引覆蓋)
db.collection_test.find(
{userid: "1003"},
{userid:1,_id:-1}
).explain()
二、API操作-快速入門
注意:該部分內容與JPA、MyBatis類似,簡單了解即可。使用的時候能查詢資料,能看懂就可以。
1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.stone</groupId>
<artifactId>mongodb-springboot</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<lombok.version>1.18.22</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</project>
2. application.yml
spring:
#數據源配置
data:
mongodb:
# 主機地址
host: 192.168.253.128
# 數據庫
database: test_db
# 默認端口是27017
port: 27017
#也可以使用uri連接
#uri: mongodb://192.168.253.128:27017/test_db
3. 啟動類
@SpringBootApplication
public class MongodbApplication {
public static void main(String[] args) {
SpringApplication.run(MongodbApplication.class, args);
}
}
4. 測試
此時,只要能正常連接,不報錯即可。
5. 創建測試集合實體類
① @Document注解
類名小寫與集合名一致則可以省略屬性配置,如果省略,則默認使用類名小寫映射集合;
假設集合名為"comment",則直接使用@Document即可。
② @CompoundIndex注解
@CompoundIndex(def = "{'userid': 1, 'nickname': -1}"),用于指定復合索引;
還是推薦在client通過指令提前生成索引,不推薦使用注解生成索引。
③ @Id注解
主鍵標識,該屬性的值會自動對應mongodb的主鍵字段"_id";
如果該屬性名就叫“id”,則該注解可以省略,否則必須寫。
④ @Field注解
該屬性對應mongodb的字段的名字,如果一致,則無需該注解。
⑤ @Indexed注解
添加了一個單字段的索引;
還是推薦在client通過指令提前生成索引,不推薦使用注解生成索引。
/**
* 文章評論實體類
*/
//把一個java類聲明為mongodb的文檔,可以通過collection參數指定這個類對應的文檔。
//@Document(collection="mongodb 對應 collection 名")
// 若未加 @Document ,該 bean save 到 mongo 的 comment collection
// 若添加 @Document ,則 save 到 comment collection
@Document(collection="collection_test")//類名小寫與集合名一致則可以省略,如果省略,則默認使用類名小寫映射集合
//復合索引
// @CompoundIndex( def = "{'userid': 1, 'nickname': -1}")
@Data //lombok的注解
public class Comment implements Serializable {
//主鍵標識,該屬性的值會自動對應mongodb的主鍵字段"_id",如果該屬性名就叫“id”,則該注解可以省略,否則必須寫
@Id //此處其實可以省略
private String id;//主鍵
//該屬性對應mongodb的字段的名字,如果一致,則無需該注解
@Field("content") //此處該注解其實可以省略
private String content;//吐槽內容
private Date publishtime;//發布日期
//添加了一個單字段的索引
@Indexed
private String userid;//發布人ID
private String nickname;//昵稱
private LocalDateTime createdatetime;//評論的日期時間
private Integer likenum;//點贊數
private Integer replynum;//回復數
private String state;//狀態
private String parentid;//上級ID
private String articleid;
}
6. 持久層接口&業務層編寫
① 持久層接口
該接口需要繼承MongoRepository接口,并指定實體類、主鍵類型,如下:
public interface CommentRepository extends MongoRepository<Comment, String> {
}
MongoRepository接口,如下:
@NoRepositoryBean
public interface MongoRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
@Override
<S extends T> List<S> saveAll(Iterable<S> entities);
@Override
List<T> findAll();
@Override
List<T> findAll(Sort sort);
<S extends T> S insert(S entity);
<S extends T> List<S> insert(Iterable<S> entities);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
可以看到基礎的插入、查詢操作都有,運行時則會生成其代理對象執行具體方法。
② 業務層
public interface CommentService {
public void saveComment(Comment comment);
public void updateComment(Comment comment);
public void deleteCommentById(String id);
public List<Comment> findCommentList();
public Comment findCommentById(String id);
}
/**
* 評論的業務層
*/
@Service
public class CommentServiceImpl implements CommentService {
//注入dao
@Autowired
private CommentRepository commentRepository;
/**
* 保存一個評論
* @param comment
*/
public void saveComment(Comment comment){
//如果需要自定義主鍵,可以在這里指定主鍵;如果不指定主鍵,MongoDB會自動生成主鍵
//設置一些默認初始值。。。
//調用dao
commentRepository.save(comment);
}
/**
* 更新評論
* @param comment
*/
public void updateComment(Comment comment){
//調用dao
commentRepository.save(comment);
}
/**
* 根據id刪除評論
* @param id
*/
public void deleteCommentById(String id){
//調用dao
commentRepository.deleteById(id);
}
/**
* 查詢所有評論
* @return
*/
public List<Comment> findCommentList(){
//調用dao
return commentRepository.findAll();
}
/**
* 根據id查詢評論
* @param id
* @return
*/
public Comment findCommentById(String id){
//調用dao
return commentRepository.findById(id).get();
}
}
7. 測試
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MongodbApplication.class)
public class CommentServiceImplTest {
//注入Service
@Autowired
private CommentService commentService;
/**
* 保存一個評論
*/
@Test
public void testSaveComment(){
Comment comment=new Comment();
comment.setArticleid("100000");
comment.setContent("測試添加的數據");
comment.setCreatedatetime(LocalDateTime.now());
comment.setUserid("1003");
comment.setNickname("凱撒大帝");
comment.setState("1");
comment.setLikenum(0);
comment.setReplynum(0);
commentService.saveComment(comment);
}
/**
* 查詢所有數據
*/
@Test
public void testFindAll(){
List<Comment> list = commentService.findCommentList();
System.out.println(list);
}
/**
* 測試根據id查詢
*/
@Test
public void testFindCommentById(){
Comment comment = commentService.findCommentById("62976eb31629ea868c6b5511");
System.out.println(comment);
}
}
8. 根據上級ID查詢分頁列表
這個地方非常特殊,必須要在實體類內設置parentid屬性,然后跟據該屬性進行分頁。
① CommentRepository新增方法定義
//根據父id,查詢子評論的分頁列表
Page<Comment> findByParentid(String parentid, Pageable pageable);
② CommentService新增方法
public Page<Comment> findCommentListPageByParentid(String parentid, int page, int size);
/**
* 根據父id查詢分頁列表
* @param parentid
* @param page
* @param size
* @return
*/
public Page<Comment> findCommentListPageByParentid(String parentid, int page, int size){
return commentRepository.findByParentid(parentid, PageRequest.of(page - 1, size));
}
③ 測試
注意:一定要先插入帶有parentid屬性的數據再測試
/**
* 測試根據父id查詢子評論的分頁列表
*/
@Test
public void testFindCommentListPageByParentid(){
Page<Comment> pageResponse = commentService.findCommentListPageByParentid("3", 1, 2);
System.out.println("----總記錄數:"+pageResponse.getTotalElements());
System.out.println("----當前頁數據:"+pageResponse.getContent());
}
9. MongoTemplate
繼承MongoRepository接口默認只能實現基礎的查詢、插入、保存操作,而且較為復雜的操作需要先查詢、再設置新數據、最后保存,效率較低。
/**
* 點贊-效率低
* @param id
*/
public void updateCommentThumbupToIncrementingOld(String id){
Comment comment = CommentRepository.findById(id).get();
comment.setLikenum(comment.getLikenum() + 1);
CommentRepository.save(comment);
}
使用MongoTemplate類可以提升此效率,用法如下:
public void updateCommentLikenum(String id);
//注入MongoTemplate
@Autowired
private MongoTemplate mongoTemplate;
/**
* 點贊數+1
*
* @param id
*/
@Override
public void updateCommentLikenum(String id) {
//查詢對象
Query query = Query.query(Criteria.where("_id").is(id));
//更新對象
Update update = new Update();
//局部更新,相當于$set
// update.set(key,value)
//遞增$inc
// update.inc("likenum",1);
update.inc("likenum");
//參數1:查詢對象
//參數2:更新對象
//參數3:集合的名字或實體類的類型Comment.class
mongoTemplate.updateFirst(query, update, "collection_test");
}
測試:
/**
* 點贊數+1
*/
@Test
public void testUpdateCommentLikenum(){
//對3號文檔的點贊數+1
commentService.updateCommentLikenum("62976eb31629ea868c6b5511");
}
三、結尾
以上即為MongoDB-基礎使用(二)的全部內容,感謝閱讀。