天天看點

學習MongoDB快速入門上手

目錄

2、MongoDB簡介

1.1、MongoDB簡介

1.2、MongoDB的特點

1.3 資料類型

3、MongoDB入門

2.1、資料庫以及表的操作

2.2、新增資料

2.3、更新資料

2.4、删除資料

2.5、查詢資料

2.6、索引

2.7、執行計劃

4、SpringData-Mongo

4.1、環境搭建

4.2、完成基本操作

2、MongoDB簡介

對于社交類軟體的功能,我們需要對它的功能特點做分析:

  • 資料量會随着使用者數增大而增大
  • 讀多寫少
  • 價值較低
  • 非好友看不到其動态内容
  • 地理位置的查詢
  • ……

針對以上特點,我們來分析一下:

  • mysql:關系型資料庫(效率低)
  • redis:redis緩存(微網誌,效率高,資料格式不豐富)
  • 對于資料量大而言,顯然不能夠使用關系型資料庫進行存儲,我們需要通過MongoDB進行存儲
  • 對于讀多寫少的應用,需要減少讀取的成本
  • 比如說,一條SQL語句,單張表查詢一定比多張表查詢要快

探花交友

  • mongodb:存儲業務資料(圈子,推薦的資料,小視訊資料,點贊,評論等)
  • redis:承擔的角色是緩存層(提升查詢效率)
  • mysql:存儲和核心業務資料,賬戶

1.1、MongoDB簡介

MongoDB:是一個高效的非關系型資料庫(不支援表關系:隻能操作單表)

學習MongoDB快速入門上手

MongoDB是一個基于分布式檔案存儲的資料庫。由C++語言編寫。旨在為WEB應用提供可擴充的高性能資料存儲解決方案。

MongoDB是一個介于關系資料庫和非關系資料庫之間的産品,是非關系資料庫當中功能最豐富,最像關系資料庫的,它支援的資料結構非常松散,是類似json的bson格式,是以可以存儲比較複雜的資料類型。

MongoDB最大的特點是它支援的查詢語言非常強大,其文法有點類似于面向對象的查詢語言,幾乎可以實作類似關系資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。

官網:https://www.mongodb.com

1.2、MongoDB的特點

MongoDB 最大的特點是他支援的查詢語言非常強大,其文法有點類似于面向對象的查詢語言,幾乎可以實作類似關系資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。它是一個面向集合的,模式自由的文檔型資料庫。具體特點總結如下:

  1. 面向集合存儲,易于存儲對象類型的資料
  2. 模式自由
  3. 支援動态查詢
  4. 支援完全索引,包含内部對象
  5. 支援複制和故障恢複
  6. 使用高效的二進制資料存儲,包括大型對象(如視訊等)
  7. 自動處理碎片,以支援雲計算層次的擴充性
  8. 支援 Python,PHP,Ruby,Java,C,C#,Javascript,Perl及C++語言的驅動程 序, 社群中也提供了對Erlang及.NET 等平台的驅動程式
  9. 檔案存儲格式為 BSON(一種 JSON 的擴充)

1.2.1、通過docker安裝MongoDB

在課程資料的虛拟機中已經提供了MongoDB的鏡像和容器,我們隻需要使用簡單的指令即可啟動

#進入base目錄

cd /root/docker-file/base/

#批量建立啟動容器,其中已經包含了redis,zookeeper,mongodb容器

docker-compose up -d

#檢視容器

docker ps -a

學習MongoDB快速入門上手

可以看到mongoDB已經啟動,對外暴露了27017的操作端口

1.2.2、MongoDB體系結構

MongoDB 的邏輯結構是一種層次結構。主要由: 文檔(document)、集合(collection)、資料庫(database)這三部分組成的。邏輯結構是面 向使用者的,使用者使用 MongoDB 開發應用程式使用的就是邏輯結構。

  1. MongoDB 的文檔(document),相當于關系資料庫中的一行記錄。
  2. 多個文檔組成一個集合(collection),相當于關系資料庫的表。
  3. 多個集合(collection),邏輯上組織在一起,就是資料庫(database)。
  4. 一個 MongoDB 執行個體支援多個資料庫(database)。 文檔(document)、集合(collection)、資料庫(database)的層次結構如下圖:
學習MongoDB快速入門上手

為了更好的了解,下面與SQL中的概念進行對比:

SQL術語/概念 MongoDB術語/概念 解釋/說明
database database 資料庫
table collection 資料庫表/集合
row document 表中的一條資料
column field 資料字段/域
index index 索引
table joins 表連接配接,MongoDB不支援
primary key primary key 主鍵,MongoDB自動将_id字段設定為主鍵
學習MongoDB快速入門上手

1.3 資料類型

  • 資料格式:BSON {aa:bb}
  • null:用于表示空值或者不存在的字段,{“x”:null}
  • 布爾型:布爾類型有兩個值true和false,{“x”:true}
  • 數值:shell預設使用64為浮點型數值。{“x”:3.14}或{“x”:3}。對于整型值,可以使用 NumberInt(4位元組符号整數)或NumberLong(8位元組符号整數), {“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}
  • 字元串:UTF-8字元串都可以表示為字元串類型的資料,{“x”:“呵呵”}
  • 日期:日期被存儲為自新紀元依賴經過的毫秒數,不存儲時區,{“x”:new Date()}
  • 正規表達式:查詢時,使用正規表達式作為限定條件,文法與JavaScript的正規表達式相 同,{“x”:/[abc]/}
  • 數組:資料清單或資料集可以表示為數組,{“x”: [“a“,“b”,”c”]}
  • 内嵌文檔:文檔可以嵌套其他文檔,被嵌套的文檔作為值來處理,{“x”:{“y”:3 }}
  • 對象Id:對象id是一個12位元組的字元串,是文檔的唯一辨別,{“x”: objectId() }
  • 二進制資料:二進制資料是一個任意位元組的字元串。它不能直接在shell中使用。如果要 将非utf-字元儲存到資料庫中,二進制資料是唯一的方式。

3、MongoDB入門

2.1、資料庫以及表的操作

#檢視所有的資料庫

> show dbs

#通過use關鍵字切換資料庫

> use admin

#建立資料庫

#說明:在MongoDB中,資料庫是自動建立的,通過use切換到新資料庫中,進行插入資料即可自動建立資料庫

> use testdb

> show dbs #并沒有建立資料庫

> db.user.insert({id:1,name:'zhangsan'})  #插入資料

> show dbs

#檢視表

> show tables

> show collections

#删除集合(表)

> db.user.drop()

true  #如果成功删除標明集合,則 drop() 方法傳回 true,否則傳回 false。

#删除資料庫

> use testdb #先切換到要删除的資料中

> db.dropDatabase()  #删除資料庫

2.2、新增資料

在MongoDB中,存儲的文檔結構是一種類似于json的結構,稱之為bson(全稱為:Binary JSON)。

#插入資料

#文法:db.表名.insert(json字元串)

> db.user.insert({id:1,username:'zhangsan',age:20})

> db.user.find()  #查詢資料

2.3、更新資料

update() 方法用于更新已存在的文檔。文法格式如下:

db.collection.update(

  <query>,

  <update>,

  [

    upsert: <boolean>,

    multi: <boolean>,

    writeConcern: <document>

  ]

)

參數說明:

  • query : update的查詢條件,類似sql update查詢内where後面的。
  • update : update的對象和一些更新的操作符(如$,$inc.$set)等,也可以了解為sql update查詢内set後面的
  • upsert : 可選,這個參數的意思是,如果不存在update的記錄,是否插入objNew,true為插入,預設是false,不插入。
  • multi : 可選,mongodb 預設是false,隻更新找到的第一條記錄,如果這個參數為true,就把按條件查出來多條記錄全部更新。
  • writeConcern :可選,抛出異常的級别。

#查詢全部

> db.user.find()

#更新資料

> db.user.update({id:1},{$set:{age:22}})

#注意:如果這樣寫,會删除掉其他的字段

> db.user.update({id:1},{age:25})

#更新不存在的字段,會新增字段

> db.user.update({id:2},{$set:{sex:1}}) #更新資料

#更新不存在的資料,預設不會新增資料

> db.user.update({id:3},{$set:{sex:1}})

#如果設定第一個參數為true,就是新增資料

> db.user.update({id:3},{$set:{sex:1}},true)

2.4、删除資料

通過remove()方法進行删除資料,文法如下:

db.collection.remove(

  <query>,

  {

    justOne: <boolean>,

    writeConcern: <document>

  }

)

參數說明:

  • query :(可選)删除的文檔的條件。
  • justOne : (可選)如果設為 true 或 1,則隻删除一個文檔,如果不設定該參數,或使用預設值 false,則删除所有比對條件的文檔。
  • writeConcern :(可選)抛出異常的級别。

執行個體:

#删除資料

> db.user.remove({})

#插入4條測試資料

db.user.insert({id:1,username:'zhangsan',age:20})

db.user.insert({id:2,username:'lisi',age:21})

db.user.insert({id:3,username:'wangwu',age:22})

db.user.insert({id:4,username:'zhaoliu',age:22})

> db.user.remove({age:22},true)

#删除所有資料

> db.user.remove({})

2.5、查詢資料

MongoDB 查詢資料的文法格式如下:

db.user.find([query],[fields])

  • query :可選,使用查詢操作符指定查詢條件
  • fields :可選,使用投影操作符指定傳回的鍵。查詢時傳回文檔中所有鍵值, 隻需省略該參數即可(預設省略)。

條件查詢:

操作 格式 範例 RDBMS中的類似語句
等于

{<key>:<value>

}

db.col.find({"by":"黑馬程式員"}).pretty()

where by = '黑馬程式員'

小于

{<key>:{$lt:<value>}}

db.col.find({"likes":{$lt:50}}).pretty()

where likes < 50

小于或等于

{<key>:{$lte:<value>}}

db.col.find({"likes":{$lte:50}}).pretty()

where likes <= 50

大于

{<key>:{$gt:<value>}}

db.col.find({"likes":{$gt:50}}).pretty()

where likes > 50

大于或等于

{<key>:{$gte:<value>}}

db.col.find({"likes":{$gte:50}}).pretty()

where likes >= 50

不等于

{<key>:{$ne:<value>}}

db.col.find({"likes":{$ne:50}}).pretty()

where likes != 50

執行個體:

#插入測試資料

db.user.insert({id:1,username:'zhangsan',age:20})

db.user.insert({id:2,username:'lisi',age:21})

db.user.insert({id:3,username:'wangwu',age:22})

db.user.insert({id:4,username:'zhaoliu',age:22})

db.user.find()  #查詢全部資料

db.user.find({},{id:1,username:1})  #隻查詢id與username字段

db.user.find().count()  #查詢資料條數

db.user.find({id:1}) #查詢id為1的資料

db.user.find({age:{$lte:21}}) #查詢小于等于21的資料

db.user.find({$or:[{id:1},{id:2}]}) #查詢id=1 or id=2

#分頁查詢:Skip()跳過幾條,limit()查詢條數

db.user.find().limit(2).skip(1)  #跳過1條資料,查詢2條資料

db.user.find().sort({id:-1}) #按照id倒序排序,-1為倒序,1為正序

2.6、索引

索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取資料時必須掃描集合中的每個檔案并選取那些符合查詢條件的記錄。

這種掃描全集合的查詢效率是非常低的,特别在處理大量的資料時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的性能是非常緻命的。

索引是特殊的資料結構,索引存儲在一個易于周遊讀取的資料集合中,索引是對資料庫表中一列或多列的值進行排序的一種結構

#建立索引

> db.user.createIndex({'age':1})

#檢視索引

> db.user.getIndexes()

[

{

"v" : 2,

"key" : {

"_id" : 1

},

"name" : "_id_",

"ns" : "testdb.user"

}

]

#說明:1表示升序建立索引,-1表示降序建立索引。

2.7、執行計劃

MongoDB 查詢分析可以確定我們建議的索引是否有效,是查詢語句性能分析的重要工具。

#插入1000條資料

for(var i=1;i<1000;i++)db.user.insert({id:100+i,username:'name_'+i,age:10+i})

#檢視執行計劃

> db.user.find({age:{$gt:100},id:{$lt:200}}).explain()

#測試沒有使用索引

> db.user.find({username:'zhangsan'}).explain()

#winningPlan:最佳執行計劃

#"stage" : "FETCH", #查詢方式,常見的有COLLSCAN/全表掃描、IXSCAN/索引掃描、FETCH/根據索引去檢索文檔、SHARD_MERGE/合并分片結果、IDHACK/針對_id進行查詢

4、SpringData-Mongo

Spring-data對MongoDB做了支援,使用spring-data-mongodb可以簡化MongoDB的操作,封裝了底層的mongodb-driver。

位址:Spring Data MongoDB

使用Spring-Data-MongoDB很簡單,隻需要如下幾步即可:

  • 導入起步依賴
  • 編寫配置資訊
  • 編寫實體類(配置注解 @Document,@Id)
  • 操作mongodb
  • 注入MongoTemplate對象,完成CRUD操作
  • 編寫Repository接口,注入接口完成基本Crud操作

4.1、環境搭建

第一步,導入依賴:

<parent>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter-parent</artifactId>

   <version>2.3.9.RELEASE</version>

</parent>

<dependencies>

   <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-data-mongodb</artifactId>

   </dependency>

   <dependency>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-test</artifactId>

       <scope>test</scope>

   </dependency>

</dependencies>

第二步,編寫application.yml配置檔案

spring:

data:

  mongodb:

    uri: mongodb://192.168.136.160:27017/test

第三步,編寫啟動類

package com.tanhua.mongo;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class MongoApplication {

   public static void main(String[] args) {

       SpringApplication.run(MongoApplication.class, args);

  }

}

4.2、完成基本操作

第一步,編寫實體類

package com.tanhua.mongo.domain;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import org.bson.types.ObjectId;

import org.springframework.data.mongodb.core.mapping.Document;

@Data

@AllArgsConstructor

@NoArgsConstructor

@Document(value="person")

public class Person {

   private ObjectId id;

   private String name;

   private int age;

   private String address;

}

package cn.itcast.mongo.test;

import cn.itcast.mongo.MongoApplication;
import cn.itcast.mongo.domain.Person;
import org.bson.types.ObjectId;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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 org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MongoApplication.class)
public class MongoTest {

    /**
     * SpringData-mongodb操作
     *    1、配置實體類
     *    2、實體類上配置注解(配置集合和對象間的映射關系)
     *    3、注入MongoTemplate對象
     *    4、調用對象方法,完成資料庫操作
     */
    @Autowired
    private MongoTemplate mongoTemplate;

    //儲存
    @Test
    public void testSave() {
        for (int i = 0; i < 10; i++) {
            Person person = new Person();
            person.setId(ObjectId.get()); //ObjectId.get():擷取一個唯一主鍵字元串
            person.setName("張三"+i);
            person.setAddress("北京順義"+i);
            person.setAge(18+i);
            mongoTemplate.save(person);
        }
    }

    //查詢-查詢所有
    @Test
    public void testFindAll() {
        List<Person> list = mongoTemplate.findAll(Person.class);
        for (Person person : list) {
            System.out.println(person);
        }
    }

    @Test
    public void testFind() {
        //查詢年齡小于20的所有人
        Query query = new Query(Criteria.where("age").lt(20)); //查詢條件對象
        //查詢
        List<Person> list = mongoTemplate.find(query, Person.class);

        for (Person person : list) {
            System.out.println(person);
        }
    }

    /**
     * 分頁查詢
     */
    @Test
    public void testPage() {
        Criteria criteria = Criteria.where("age").lt(30);
        //1、查詢總數
        Query queryCount = new Query(criteria);
        long count = mongoTemplate.count(queryCount, Person.class);
        System.out.println(count);
        //2、查詢目前頁的資料清單, 查詢第二頁,每頁查詢2條
        Query queryLimit = new Query(criteria)
                .limit(2)//設定每頁查詢條數
                .skip(2) ; //開啟查詢的條數 (page-1)*size
        List<Person> list = mongoTemplate.find(queryLimit, Person.class);
        for (Person person : list) {
            System.out.println(person);
        }
    }


    /**
     * 更新:
     *    根據id,更新年齡
     */
    @Test
    public void testUpdate() {
        //1、條件
        Query query = Query.query(Criteria.where("id").is("5fe404c26a787e3b50d8d5ad"));
        //2、更新的資料
        Update update = new Update();
        update.set("age", 20);
        mongoTemplate.updateFirst(query, update, Person.class);
    }

    @Test
    public void testRemove() {
        Query query = Query.query(Criteria.where("id").is("5fe404c26a787e3b50d8d5ad"));
        mongoTemplate.remove(query, Person.class);
    }
}