MongoDB-基礎(chǔ)使用(二)

前置文章:
MongoDB-基礎(chǔ)使用(一),該文主要介紹MongoDB概念、安裝、庫/集合(表)/文檔(行)操作。

零、本文綱要

一、索引

  1. 索引類型
  2. 索引管理操作
  3. 索引使用

二、API操作-快速入門

  1. pom.xml
  2. application.yml
  3. 啟動(dòng)類
  4. 測(cè)試
  5. 創(chuàng)建測(cè)試集合實(shí)體類
  6. 持久層接口&業(yè)務(wù)層編寫
  7. 測(cè)試
  8. 根據(jù)上級(jí)ID查詢分頁列表
  9. MongoTemplate

一、索引

MongoDB索引使用B樹數(shù)據(jù)結(jié)構(gòu)(確切的說是B-Tree,MySQL是B+Tree)

注意:該部分的內(nèi)容與Redis、JS類似,整體特性又與MySQL相近。可以簡(jiǎn)單了解以下。

1. 索引類型

a、單字段索引
b、復(fù)合索引
c、地理空間索引
d、文本索引
e、哈希索引

2. 索引管理操作

① 索引查看

# 索引查看
db.collection.getIndexes()
#如:
db.collection_test.getIndexes()
> db.collection_test.getIndexes()
[
    {
        "v" : 2,                            #索引的版本號(hào)
        "key" : {                           #索引的字段
            "_id" : 1                       #1代表升序
        },
        "name" : "_id_",                    #索引的名稱,默認(rèn)為 "字段名_" + "升降序規(guī)則數(shù)字",如:"userid_1_nickname_-1"
        "ns" : "db_test.collection_test"    #命名空間,數(shù)據(jù)庫.集合
    }
]

② 索引創(chuàng)建

# 創(chuàng)建單字段索引
db.collection.createIndex(keys, options)
#如:
db.collection_test.createIndex({userid: 1}) #此處1代表升序,-1則為降序,單字段索引升降序不影響整體查詢效率

# 創(chuàng)建復(fù)合索引
#如:
db.collection_test.createIndex({userid: 1, nickname: -1})

以下了解即可:

參數(shù) 類型 描述
background Boolean 建索引過程會(huì)阻塞其它數(shù)據(jù)庫操作,background可指定以后臺(tái)方式創(chuàng)建索引,即增加 "background" 可選參數(shù)。 "background" 默認(rèn)值為false
unique Boolean 建立的索引是否唯一。指定為true創(chuàng)建唯一索引。默認(rèn)值為false.
name string 索引的名稱。如果未指定,MongoDB的通過連接索引的字段名和排序順序生成一個(gè)索引名稱。
dropDups Boolean 3.0+版本已廢棄。在建立唯一索引時(shí)是否刪除重復(fù)記錄,指定 true 創(chuàng)建唯一索引。默認(rèn)值為 false.
sparse Boolean 對(duì)文檔中不存在的字段數(shù)據(jù)不啟用索引;這個(gè)參數(shù)需要特別注意,如果設(shè)置為true的話,在索引字段中不會(huì)查詢出不包含對(duì)應(yīng)字段的文檔.。默認(rèn)值為 false.
expireAfterSeconds integer 指定一個(gè)以秒為單位的數(shù)值,完成 TTL設(shè)定,設(shè)定集合的生存時(shí)間。
v index version 索引的版本號(hào)。默認(rèn)的索引版本取決于mongod創(chuàng)建索引時(shí)運(yùn)行的版本。
weights document 索引權(quán)重值,數(shù)值在 1 到 99,999 之間,表示該索引相對(duì)于其他索引字段的得分權(quán)重。
default_language string 對(duì)于文本索引,該參數(shù)決定了停用詞及詞干和詞器的規(guī)則的列表。 默認(rèn)為英語
language_override string 對(duì)于文本索引,該參數(shù)指定了包含在文檔中的字段名,語言覆蓋默認(rèn)的language,默認(rèn)值為 language.

③ 索引移除

# 索引移除
db.collection.dropIndex(index)
#如:
db.collection_test.dropIndex("userid_1")
db.collection_test.dropIndex({userid: 1})

# 移除所有索引(默認(rèn)"_id_"索引不會(huì)被移除)
db.collection_test.dropIndexes()

3. 索引使用

① 執(zhí)行計(jì)劃

# 執(zhí)行計(jì)劃
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操作-快速入門

注意:該部分內(nèi)容與JPA、MyBatis類似,簡(jiǎn)單了解即可。使用的時(shí)候能查詢資料,能看懂就可以。

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:
#數(shù)據(jù)源配置
  data:
    mongodb:
      # 主機(jī)地址
      host: 192.168.253.128
      # 數(shù)據(jù)庫
      database: test_db
      # 默認(rèn)端口是27017
      port: 27017
      #也可以使用uri連接
      #uri: mongodb://192.168.253.128:27017/test_db

3. 啟動(dòng)類

@SpringBootApplication
public class MongodbApplication {
    public static void main(String[] args) {
        SpringApplication.run(MongodbApplication.class, args);
    }
}

4. 測(cè)試

此時(shí),只要能正常連接,不報(bào)錯(cuò)即可。

5. 創(chuàng)建測(cè)試集合實(shí)體類

① @Document注解

類名小寫與集合名一致則可以省略屬性配置,如果省略,則默認(rèn)使用類名小寫映射集合;
假設(shè)集合名為"comment",則直接使用@Document即可。

② @CompoundIndex注解

@CompoundIndex(def = "{'userid': 1, 'nickname': -1}"),用于指定復(fù)合索引;
還是推薦在client通過指令提前生成索引,不推薦使用注解生成索引。

③ @Id注解

主鍵標(biāo)識(shí),該屬性的值會(huì)自動(dòng)對(duì)應(yīng)mongodb的主鍵字段"_id";
如果該屬性名就叫“id”,則該注解可以省略,否則必須寫。

④ @Field注解

該屬性對(duì)應(yīng)mongodb的字段的名字,如果一致,則無需該注解。

⑤ @Indexed注解

添加了一個(gè)單字段的索引;
還是推薦在client通過指令提前生成索引,不推薦使用注解生成索引。

/**
 * 文章評(píng)論實(shí)體類
 */
//把一個(gè)java類聲明為mongodb的文檔,可以通過collection參數(shù)指定這個(gè)類對(duì)應(yīng)的文檔。
//@Document(collection="mongodb 對(duì)應(yīng) collection 名")
// 若未加 @Document ,該 bean save 到 mongo 的 comment collection
// 若添加 @Document ,則 save 到 comment collection
@Document(collection="collection_test")//類名小寫與集合名一致則可以省略,如果省略,則默認(rèn)使用類名小寫映射集合
//復(fù)合索引
// @CompoundIndex( def = "{'userid': 1, 'nickname': -1}")
@Data //lombok的注解
public class Comment implements Serializable {
    //主鍵標(biāo)識(shí),該屬性的值會(huì)自動(dòng)對(duì)應(yīng)mongodb的主鍵字段"_id",如果該屬性名就叫“id”,則該注解可以省略,否則必須寫
    @Id //此處其實(shí)可以省略
    private String id;//主鍵
    //該屬性對(duì)應(yīng)mongodb的字段的名字,如果一致,則無需該注解
    @Field("content") //此處該注解其實(shí)可以省略
    private String content;//吐槽內(nèi)容
    private Date publishtime;//發(fā)布日期
    //添加了一個(gè)單字段的索引
    @Indexed
    private String userid;//發(fā)布人ID
    private String nickname;//昵稱
    private LocalDateTime createdatetime;//評(píng)論的日期時(shí)間
    private Integer likenum;//點(diǎn)贊數(shù)
    private Integer replynum;//回復(fù)數(shù)
    private String state;//狀態(tài)
    private String parentid;//上級(jí)ID
    private String articleid;
}

6. 持久層接口&業(yè)務(wù)層編寫

① 持久層接口

該接口需要繼承MongoRepository接口,并指定實(shí)體類、主鍵類型,如下:

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);

可以看到基礎(chǔ)的插入、查詢操作都有,運(yùn)行時(shí)則會(huì)生成其代理對(duì)象執(zhí)行具體方法。

② 業(yè)務(wù)層

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);
}

/**
 * 評(píng)論的業(yè)務(wù)層
 */
@Service
public class CommentServiceImpl implements CommentService {

    //注入dao
    @Autowired
    private CommentRepository commentRepository;

    /**
     * 保存一個(gè)評(píng)論
     * @param comment
     */
    public void saveComment(Comment comment){
        //如果需要自定義主鍵,可以在這里指定主鍵;如果不指定主鍵,MongoDB會(huì)自動(dòng)生成主鍵
        //設(shè)置一些默認(rèn)初始值。。。
        //調(diào)用dao
        commentRepository.save(comment);
    }

    /**
     * 更新評(píng)論
     * @param comment
     */
    public void updateComment(Comment comment){
        //調(diào)用dao
        commentRepository.save(comment);
    }

    /**
     * 根據(jù)id刪除評(píng)論
     * @param id
     */
    public void deleteCommentById(String id){
        //調(diào)用dao
        commentRepository.deleteById(id);
    }

    /**
     * 查詢所有評(píng)論
     * @return
     */
    public List<Comment> findCommentList(){
        //調(diào)用dao
        return commentRepository.findAll();
    }

    /**
     * 根據(jù)id查詢?cè)u(píng)論
     * @param id
     * @return
     */
    public Comment findCommentById(String id){
        //調(diào)用dao
        return commentRepository.findById(id).get();
    }
}

7. 測(cè)試

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MongodbApplication.class)
public class CommentServiceImplTest {
    //注入Service
    @Autowired
    private CommentService commentService;
    /**
     * 保存一個(gè)評(píng)論
     */
    @Test
    public void testSaveComment(){
        Comment comment=new Comment();
        comment.setArticleid("100000");
        comment.setContent("測(cè)試添加的數(shù)據(jù)");
        comment.setCreatedatetime(LocalDateTime.now());
        comment.setUserid("1003");
        comment.setNickname("凱撒大帝");
        comment.setState("1");
        comment.setLikenum(0);
        comment.setReplynum(0);
        commentService.saveComment(comment);
    }
    /**
     * 查詢所有數(shù)據(jù)
     */
    @Test
    public void testFindAll(){
        List<Comment> list = commentService.findCommentList();
        System.out.println(list);
    }
    /**
     * 測(cè)試根據(jù)id查詢
     */
    @Test
    public void testFindCommentById(){
        Comment comment = commentService.findCommentById("62976eb31629ea868c6b5511");
        System.out.println(comment);
    }
}

8. 根據(jù)上級(jí)ID查詢分頁列表

這個(gè)地方非常特殊,必須要在實(shí)體類內(nèi)設(shè)置parentid屬性,然后跟據(jù)該屬性進(jìn)行分頁。

① CommentRepository新增方法定義

//根據(jù)父id,查詢子評(píng)論的分頁列表
Page<Comment> findByParentid(String parentid, Pageable pageable);

② CommentService新增方法

public Page<Comment> findCommentListPageByParentid(String parentid, int page, int size);
/**
* 根據(jù)父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));
}

③ 測(cè)試

注意:一定要先插入帶有parentid屬性的數(shù)據(jù)再測(cè)試

/**
 * 測(cè)試根據(jù)父id查詢子評(píng)論的分頁列表
 */
@Test
public void testFindCommentListPageByParentid(){
    Page<Comment> pageResponse = commentService.findCommentListPageByParentid("3", 1, 2);
    System.out.println("----總記錄數(shù):"+pageResponse.getTotalElements());
    System.out.println("----當(dāng)前頁數(shù)據(jù):"+pageResponse.getContent());
}

9. MongoTemplate

繼承MongoRepository接口默認(rèn)只能實(shí)現(xiàn)基礎(chǔ)的查詢、插入、保存操作,而且較為復(fù)雜的操作需要先查詢、再設(shè)置新數(shù)據(jù)、最后保存,效率較低。

/**
* 點(diǎn)贊-效率低
* @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;

/**
 * 點(diǎn)贊數(shù)+1
 *
 * @param id
 */
@Override
public void updateCommentLikenum(String id) {
    //查詢對(duì)象
    Query query = Query.query(Criteria.where("_id").is(id));
    //更新對(duì)象
    Update update = new Update();
    //局部更新,相當(dāng)于$set
    // update.set(key,value)
    //遞增$inc
    // update.inc("likenum",1);
    update.inc("likenum");
    //參數(shù)1:查詢對(duì)象
    //參數(shù)2:更新對(duì)象
    //參數(shù)3:集合的名字或?qū)嶓w類的類型Comment.class
    mongoTemplate.updateFirst(query, update, "collection_test");
}

測(cè)試:

/**
* 點(diǎn)贊數(shù)+1
*/
@Test
public void testUpdateCommentLikenum(){
    //對(duì)3號(hào)文檔的點(diǎn)贊數(shù)+1
    commentService.updateCommentLikenum("62976eb31629ea868c6b5511");
}

三、結(jié)尾

以上即為MongoDB-基礎(chǔ)使用(二)的全部?jī)?nèi)容,感謝閱讀。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容