本文主要記錄近期學習 MongoDB 的一些內容,主要參考了官方文檔 https://docs.mongodb.com/v4.4/,MongoDB 的官方文檔寫的還是挺不錯的,很詳細,值得一看。
本文包含以下幾部分內容:
- 認識 MongoD
- 文檔的 CRUD 操作
- 聚合操作
- 索引
- 事務
- 副本集
下邊 MongoDB 的相關操作都是在 Mongo Shell 中執行的,這種方式不需要考慮語言環境的問題,具有一定的通用性,也足以應對一些不是特別複雜的操作,作爲 MongoDB 入門也足夠了。
一、認識 MongoD
MongoDB 屬於 NoSQL 類型數據庫的一種,它具有高性能、高可用、易擴展等特點。
MongoDB 是一個文檔數據庫,它以 Binary JSON(BSON)
的數據結構來存儲文檔格式的數據,簡單的說一條文檔數據就類似於 JSON 對象,即鍵值對的形式,借用官方的以一張圖來認識下文檔數據:
其中 field 是字符串類型,但是 value 支持的數據類型相比傳統的 JSON 更加豐富,後邊我們細聊。
爲了直觀的認識一下 MongoDB,我們來對比常見的關係型數據庫 MySQL,兩者還是有很多相似的地方:
MySQL | MongoDB |
---|---|
Database(數據庫) | Database(數據庫) |
Table(表) | Collection(集合) |
Row(行) | Document(文檔) |
Column(列) | Field(字段) |
Primary Key(主鍵) | Primary Key(主鍵) |
Index(索引) | Index(索引) |
Transactions(事務) | Transactions(事務) |
1.1、一些特點
每一種數據庫都有自身相對適用的場景,如果我們的需求大致符合以下的場景,就可以考慮使用 MongoDB,這樣可用更低的成本來解決問題:
- 需要支持事務,從 MongoDB4.0 版本開始已經逐步完善了對事務的支持,開始支持多文檔事務,通過分佈式事務,事務可以跨多個操作、集合、數據庫、文檔和分片使用。
- 不需要複雜的多表關聯查詢(join),在 MongoDB 中使用 Aggregation Pipeline 中的 $lookup 操作符可以簡單的實現 left outer join。
- 對文本以及地理位置數據的存儲、查詢有較強烈的需求。當然特別專業的文本檢索還是需要用搜素引擎的,比如 Elasticsearch
- 數據模型可能有比較頻繁的變更
- 有高併發的數據讀寫需求
- 需要存儲大規模的數據
- 對數據庫的擴展性以及可用性有較高的需求
1.2、常用數據類型
也就是 BSON 中支持的數據類型:https://docs.mongodb.com/manual/reference/bson-types/
類型 | 說明 |
---|---|
ObjectId | 是一個 12 字節的 16 進制數,每個字節佔兩位,總長度爲 24 位。具體是由 4 字節的時間戳(以 Unix 紀元以來的秒數爲單位)、5 字節的根據機器和進程生成的唯一隨機值、3 字節的遞增計數器值(使用前邊的隨機值作爲起始值)組成。每條文檔數據都有一個默認字段_id 作爲主鍵,如果沒有指定值,MongoDB 會指定一個 ObjectId 類型的默認值 |
String | 必須是 UTF-8 編碼格式的字符串 |
Double | 浮點數,MongoDB 中沒有 Float 類型 |
Decimal128 | 高精度浮點數,可用於存儲價格等數據 |
Integer | 分爲 32 位(NumberInt)和 64(NumberLong)位兩種整數 |
Boolean | true 或者 false |
Object | 對象,可用於嵌入另外一個文檔 |
Null | 存儲空值 |
Array | 用於存儲數組或者列表 |
Date | 日期,是一個 64 位整數,從 1970.1.1(Unix 紀元)到現在的毫秒數, 也稱爲 UTC 日期時間,推薦使用 Date 類型處理日期 |
Timestamp | 時間戳,64位,前 32 位是從 1970.1.1(Unix 紀元)到現在的秒數,後 32 位是給定秒內操作的遞增序數,無法與 Date 類型關聯,主要供內部 MongoDB 使用,在單個 mongod 實例中,時間戳值始終是唯一的 |
Regular Expression | 存儲正則表達式 |
Code | 存儲 JavaScript 代碼 |
Binary Data | 存儲二進制數據 |
1.3、數據庫、集合、文檔
https://docs.mongodb.com/v4.4/core/databases-and-collections/
MongoDB 將數據記錄以文檔(Document
)的形式保存集合(Collection
)中、集合又需要存儲到對應的數據庫(Database
)中,所以掌握它們的一些常用操作。
MongoDB 中對數據庫、集合、文檔 field 等的命名規範以及長度都有一定的限制,可以參考官方文檔查看 。
MongoDB 的安裝可以參考文章最後一部分,起動安裝的 MongoDB 節點,然後連接到主節點:
mongo -u <user> -p <pass> --host <host> --port <port>
除了mongo
之外,其它參數都是可選的,host
、port
默認是本機的27017
端口。
1.3.1、創建、切換數據庫
use mydb
通過use
命令可以切換到指定的已存在的數據庫,如果數據庫不存在,則會在第一次給數據庫創建集合時創建對應的數據庫。
1.3.2、查看所有的數據庫
show dbs
show databases
上邊兩個命令都可以查看權限內的所有數據庫。
1.3.3、查看當前所在的數據庫
db
1.3.4、刪除數據庫
db.dropDatabase()
切換到指定數據庫後,纔可以刪除數據庫。
1.3.5、查看數據庫中的所有集合
show collections
先切換到指定數據,纔可以查看其中的集合。
1.3.6、創建集合
db.createCollection("book")
這種屬於指定集合名稱顯式的創建方式,需要先切換到指定數據庫。
除了顯式的創建集合,還在隱式創建,如果集合不存在,當第一往集合中保存數據時就會自動創建對應的集合,比如:
db.book.inserOne({})
1.3.7、刪除集合
db.book.drop()
切換到指定數據庫後,就可以根據名稱來刪除集合。
二、文檔的 CRUD 操作
https://docs.mongodb.com/v4.4/crud/
2.1、插入
2.1.1、insertOne()
insertOne()
是給指定集合中插入單條文檔,如果文檔沒有指定_id
字段,則 MongoDB 會添加一個值爲 ObjectId _id 字段到文檔中,注意 _id 字段爲默認主鍵。
db.book.insertOne({
"author": "劉慈欣",
"commentCount": 1038006,
"img": "//img14.360buyimg.com/n1/s200x200_jfs/t1705/189/702227414/177982/cc8c12f0/55dab54dN5271c377.jpg",
"name": "中國科幻基石叢書:三體(套裝1-3冊)",
"price": 83.7,
"publisher": "重慶出版社",
"shop": "科幻世界京東自營店",
"skuId": "11757834"
})
插入數據時如果不指定字段的類型,則 MongoDB 會使用自推斷出數據類型來存儲數據,但這可能不是你需要的理想類型。
2.1.2、insertMany()
如果要一次插入多條文檔,可以使用insertMany()
,並以數組形式傳入文檔,_id
字段的處理規則和上邊一致。
db.book.insertMany([
{
"author": "紫金陳",
"commentCount": 36164,
"img": "//img14.360buyimg.com/n1/s200x200_jfs/t1/130390/12/10177/391461/5f63788cE9b818814/fa5465bd1280778e.jpg",
"name": "長夜難明(紫金陳社會派懸疑推理小說必讀 迷霧劇場廖凡白宇出演的網劇《沉默的真相》原著小說)",
"price": 42,
"publisher": "雲南人民出版社",
"shop": "浦睿文化京東自營店",
"skuId": "12081064"
},
{
"author": "魯迅",
"commentCount": 25567,
"img": "//img11.360buyimg.com/n1/s200x200_g15/M0A/0F/18/rBEhWFJeUd4IAAAAAAbFh_6HtZsAAENlQKKQEoABsWf482.jpg",
"name": "吶喊",
"price": 10.6,
"publisher": "譯林出版社",
"shop": "鳳凰壹力京東自營店",
"skuId": "11338556"
}
])
2.1.3、insert()
insert()
既可以用來給集合中插入單條文檔,也可以通過數組參數插入多條文檔。
db.book.insert({})
db.book.insert([{}, {}])
2.2、查詢
查詢主要是通過find(query, projection)
方法來實現的,find()
會返回符合條件的全部文檔,但需要注意在 mongo shell 中並不是一次性返回集合中的全部文檔。
比如下邊的查詢(沒有查詢條件{}
可以省略):
db.book.find({})
該查詢實際會返回一個遊標(cursor),但我們沒有通過定義var
變量接收遊標,所以遊標會自動迭代最多 20 次,所以該查詢最多返回 20 條文檔。
如果我們通過變量來接收返回的遊標,並手動調用遊標變量,同樣遊標會自動迭代 20 次,並返回對應的文檔:
> var c = db.book.find({})
> c
> c
當然也可以手動迭代,逐條返回數據:
> var c = db.book.find({})
> while (c.hasNext()) {
printjson(c.next());
}
這個默認的 20 次可以通過如下方式修改:
DBQuery.shellBatchSize = 30
MongoDB 中提供了許多查詢相關的操作符,來滿足不同的場景,
2.2.1、比較運算符
比較運算符有$eq
、$gt
、$gte
、$lt
、$lte
、$ne
、$in
、$nin
,我們來看幾個例子
比如查詢author
的是紫金陳
的文檔:
db.book.find({author: {$eq: "紫金陳"}})
也可以使用下邊的簡化寫法:
db.book.find({author: "紫金陳"})
但需要注意,如果使用$eq
時查詢條件的值是正則表達式,那麼只會匹配字段值也是正則表達式的文檔,比如下邊的模糊查詢是沒有結果的:
db.book.find({author: {$eq: /金/}})
需要使用如下的查詢方式才能查詢到author
中包含金
的文檔:
db.book.find({author: /金/})
db.book.find({author: {$regex: /金/}})
查詢price
小於100
的書:
db.book.find({price: {$lt: 100}})
查詢author
是紫金陳
或者魯迅
的文檔:
db.book.find({author: {$in: ["紫金陳", "魯迅"]}})
這個功能也可以使用邏輯運算符$or
實現,但這種場景還是建議使用$in
詳細內容可參考文檔:https://docs.mongodb.com/v4.4/reference/operator/query-comparison/
2.2.2、邏輯運算符
邏輯運算符有$and
、$or
、$not
、$nor
。
比如查詢name
是吶喊
並且price
小於等於50
的文檔,可以使用$and
:
db.book.find({$and: [{name: "吶喊"}, {price: {$lte: 50}}]})
還有一種等價簡單的寫法,提供了隱式的$and
操作:
db.book.find({name: "吶喊", price: {$lte: 50}})
查詢price
小於 100 或者commentCount
大於100000的文檔,可以使用$or
:
db.book.find($or: [{price: {$lt: 100}}, {commentCount: {$gt: 100000}}])
$not
表示邏輯非操作,即對查詢條件取反,同時也會查詢不包含對應字段的文檔,如下查詢語句:
db.book.find({price: {$not: {$lt: 100}}})
會查詢price
大於 100 或者不包含price
的文檔。
$nor
會返回不匹配所有指定字段的查詢條件的文檔,比如:
db.book.find($nor: [{author: "魯迅"}, {commentCount: {$gt: 100000}}])
會查詢author
不是魯迅
、commentCount
不大於 100000、以及不包含對應字段的文檔。
2.2.3、文檔字段與查詢
2.2.3.1
find()
方法默認會返回文檔的全部字段,我們可以通過它的第二個參數來指定只返回哪些字段和不返回那些字段。
db.book.find({}, {name: 1})
理論上我們希望返回的文檔只有name
字段,但其實也包含_id
字段,因爲_id
字段比較特殊我們可以手動指定不返回:
db.book.find({}, {name: 1, _id: 0}
所以1
表示只會返回對應的字段,其它字段不返回(_id
需要單獨指定);0
表示不會返回對應的字段,其它字段不受影響。
2.2.3.2
有時我們需要查詢存在某個字段的文檔,可以使用$exists
:
db.book.find({img: {$exists: true}})
上邊會查詢有img
字段的文檔。
2.2.3.3
還可以按照字段類型還查詢文檔數據,$type
可以用來查詢字段值爲指定 BSON 類型的文檔:
db.book.find({commentCount: {$type: "long"}})
也可以用數組表示多個類型:
db.book.find({commentCount: {$type: ["long", "string"]}})
2.2.3.4
要獲取一個字段的類型,可以使用typeof
:
typeof db.book.name
要判斷一個字段是否爲指定類型,可以使用instanceof
:
db.book.commentCount instanceof NumberInt
2.2.3.5
mongo 中關於null
值的查詢比較特殊,如下查詢會返回img
字段值爲null
以及不存在該字段的文檔:
db.book.find(img: null)
2.2.4、排序
find()
方法查詢到的結果默認按_id
升序排列,我們也可以使用sort()
方法按照指定字段來排序。
db.book.find().sort({price: 1})
price: 1
表示查詢結果按照price
升序排列,1
表示升序、-1
表示降序。
也可以同時用多個字段排序:
db.book.find().sort({price: 1, commentCount: -1})
2.2.5、分頁
分頁查詢一般通過limit()
、skip()
兩個方法結合實現:
- limit: 控制每次查詢返回的文檔數量
- skip: 從查詢結果中跳過指定數量的文檔再開始返回
db.book.find().sort({price: 1}).limit(10).skip(20)
從查詢結果中跳過20條數據後取10條數據返回,即第三次分頁查詢。
這種方式用起來簡單,但是當數據量比較大的時候,比如幾十萬到一百萬左右,越往後分頁查詢就越慢,有比較明顯的性能問題。所以不太適合大量數據的全量分頁查詢,只查詢少量數據還是可以的。
當然在實際中也是有大量數據的全量分頁查詢需求的,此時我們可以指定一個排序字段,保證字段值按一定的規律增長即可。這樣每次查詢時需要攜帶一個排序字段的基準值,查詢前先按照排序字段排序,再查詢排序字段值大於或小於該基準值的指定數據量數據。
2.3、更新
更新文檔的方法可以指定三個參數:
-
filter
,文檔的過濾條件也就是要更新哪些文檔 -
update
,如何更新文檔 -
options
, 可選參數,指定一些額外的屬性
具體的可以參考文檔 https://docs.mongodb.com/v4.4/reference/update-methods/
比如要更新匹配過濾條件的第一條文檔,可以使用updateOne()
:
db.book.updateOne({skuId: "11757834"}, {$set: {price: 66.6}, $currentDate: {lastModified: true}}, {upsert: true})
{skuId: "11757834"}
是過濾條件,$set
操作符用來更新指定字段的值。$currentDate
操作符用來將lastModified
字段的值更新爲當前時間(默認 Date)(如果該字段不存在則會自動創建)。upsert
是可選屬性,要更新的文檔不存在時決定是否插入新文檔。
updateMany()
和updateOne()
用法類似,但是會更新匹配條件的全部文檔,比如將指定作者的書調價:
db.book.updateMany({author: "魯迅"}, {$inc: {price: 2}})
還有一個update()
方法,可以通過指定第三個參數的multi
屬性來決定是更新單個文檔還是多個文檔。
除了上邊用的$set
、$currentDate
、$inc
這幾個更新操作符之外,其它的可以參考文檔 https://docs.mongodb.com/manual/reference/operator/update/
最後還有一個replaceOne()
方法,可以用新文檔替換掉符合過濾條件的第一個文檔。
2.4、刪除
刪除操作相對簡單一些,根據指定的過濾條件,可以一次最多刪除一條,也可以刪除全部。
deleteOne()
每次最多刪除一條文檔:
db.book.deleteOne({author: "魯迅"})
deleteMany()
則可以刪除全部符合條件的。
還有一個remove()
方法,可以通過justOne
屬性指定一次刪除最多一條還是全部:
db.book.remove({author: "魯迅"}, {justOne: false})
三、聚合操作
除了一般的查詢操作,MongoDB 提供的聚合查詢也是非常有用的,主要可以實現對文檔數據的統計、分析功能。這裏我們主要了解一下聚合管道
,至於Map-Reduce
就不討論了,它基本可以由聚合管道
代替,同時可以獲得更高的性能以及可以用性。最後還有一些簡單的聚合操作方法
可以瞭解下,方便處理一下簡單的需求。
詳細的內容可以直接參考官方文檔 Aggregation。
3.1、聚合管道
聚合管道,類似於流水線處理,對輸入的文檔進行一個或者多個階段的連續處理,上一個處理階段的輸出作爲下一個階段的輸入,直到所有階段全部完成後輸出最終的處理結果。
先看一個例子來感受一下這個過程,比如先過濾出commentCount
大於 100000 的文檔、再按author
字段分組並統計出組內總的文檔數bookCount
、然後按照bookCount
降序排列:
db.book.aggregate([
{$match: {commentCount: {$gt: 100000}}},
{$group: {_id: "$author", bookCount: {$sum: 1}}},
{$sort: {bookCount: -1}}
])
經過上邊三個階段的處理,最終的結果如下:
在聚合管道中,每一個階段(Stage)都需要指定一個操作符來做具體的事情,比如前邊的$match
、$group
、$sort
。目前官方提供了大約 30 個階段操作符,具體的可以參考文檔 Aggregation Pipeline Stages,每個操作符都有詳細的用法。
這裏簡單介紹一下,知道每個操作符大概是做什麼的,可以在那些場景使用:
-
$match
,從中的文檔數據中過濾出符合查詢條件的 -
$group
,對文檔按指定字段進行分組,字段的值相同的會被分爲一組,同時可以對組內數據進行各種計算操作,最後爲每組輸出一個文檔,分組也可以實現數據去重的效果 -
$bucket
,功能和$group
類似也會對文檔分組,但是它可以指定分組字段的值的區間,對應區間的文檔會被分爲一組 -
$sort
,對文檔按指定字段排序,可以指定多個字段,-1
降序、1
升序 -
$count
,返回管道中當前階段的文檔數 -
$sortByCount
,對輸入的文檔按指定字段的值進行分組,然後計算每組的文檔數,相當於$group
+$sort
-
$skip
,跳過指定個數的文檔,將剩餘的傳遞到下一階段 -
$limit
,指定傳遞到下一階段的文檔數 -
$project
,給文檔添加新字段或者刪除已有字段,即重構文檔結構 -
$addFields
,給文檔中添加新字段,它還有一個別名$set
,和$project
的添加功能類似 -
$unset
,從文檔中刪除已有的字段,和$project
的刪除功能類似 -
$unwind
,對文檔中的數組類型字段進行結構操作,即將數組值拆分成多個元素,每個元素值將會替換原數組的值並且和當前文檔的其它字段組成一個新的文檔 -
$lookup
,主要的功能是兩個集合之間的關聯查詢,類似於 MySQL 中的 left join -
$unionWith
,可以將兩個集合的管道處理結果集組合成一個新的結果集(不會去重),然後輸入到管道中的下一階段 -
$out
,必須出現在聚合管道的最後一個階段,將前邊管道返回的文檔寫入指定的集合中
3.2、簡單的聚合操作
簡單的聚合操作主要是針對單個集合中文檔的操作,功能都很簡單。
前幾個都是統計集合中文檔數的。
3.2.1、count()
db.book.count({author: "魯迅"})
使用count()
方法時儘量不要省略過濾條件,否則會使用元數據來計數,在分片集羣上、非常正關機可能導致結果不準確。
上邊的計數統計也等價於:
db.book.find({author: "魯迅"}).count()
除了設置過濾條件,還支持可選的參數,比如設置最多統計的文檔數,避免統計過多的數據做無用功:
db.book.count({author: "魯迅", commentCount: {$gt: 100000}}, {limit: 10000})
3.2.2、estimatedDocumentCount()
db.book.estimatedDocumentCount()
這個不方法支持過濾條件,它直接使用元數據來計數,也存在上邊count()
方法的問題
3.2.3、countDocuments()
db.book.countDocuments({author: "魯迅"})
這個方法支持過濾條件以及一些可以選的參數(比如limit
),它不會使用元數據統計文檔數量,而是通過文檔的聚合返回準確的統計結果。而且沒有上邊兩個方法存在的問題。
3.2.4、distinct()
在單個集合中根據指定的過濾條件查找指定字段的不同值,類似於去重,並且以數組形式返回字段的值,比如
db.book.distinct("author", {commentCount: {$gt: 100000}})
四、索引
4.1、認識索引
MongoDB 中的索引和 MySQL 中的類似,MongoDB 中使用索引可以高效的進行數據查詢,如果不使用索引,查詢過程中就必須掃描集合中的每個文檔,進而找到匹配查詢條件的,有了索引了,則會從索引中找到匹配查詢條件的文檔。
MongoDB 中的索引是集合級別的,可以給文檔中任何字段(包括嵌套的子字段)創建索引,索引使用 B-tree 的數據結構,它會存儲作爲索引的字段的值,並且按照字段值升序或降序排列,來提高查詢的效率。
借用官方的一張圖來看一下使用索引時的查詢過程:
4.2、創建索引
MongoDB 在創建集合時,默認會在_id
字段上創建唯一索引,索引名爲_id_
並且該索引不能被刪除,這樣也可以保證_id
字段值相同的文檔不會被重複插入到集合中。
除了默認的_id
字段上的索引,我們也可以使用createIndex()
方法給其它字段創建索引。
首先可以給單個字段創建索引,比如:
db.book.createIndex({skuId: -1}, {name: "skuIdIndex"})
上邊給
author
字段創建了索引,-1
表示創建降序索引,即索引中的值按降序排列,1
則表示升序索引,對於單字段索引,使用降序或升序都可以,因爲 MongoDB 可以從任意一個方向來遍歷索引。name
則用來指定索引的名稱,也可以直接使用默認值,索引的默認名稱由索引鍵
(指定的字段名)和索引鍵方向
(-1或1)使用下劃線拼接成,上邊例子的默認索引名就是skuId_-1
。
最後可以查看創建好的索引:
此時也可以看到 MongoDB 在_id
字段上創建的默認索引。
除了上邊的單字段索引,還有複合索引,使用複合索引可以同時在多個字段上創建索引,此時字段之間的順序很重要,這也決定了索引中數據排序的先後順序。如下創建一個複合索引:
db.book.createIndex({auther: 1, name: 1})
這裏沒有指定索引名稱,而是使用默認的,查看創建好的索引:
五、事務
在 MongoDB4.0 版本之前, 僅對單個文檔的操作是具有原子性的,即單文檔事務,這裏因爲 MongoDB 中文檔是可以嵌套子文檔的,這樣就解決了一般關係型數據庫需要多張表才能描述不同數據之間關係的問題,所以這樣也能在一定程度上保證數據的一致性。
但是對於同一集合或者不同集合甚至不同數據庫中的多個文檔的讀寫就不能保證原子性了,但這個需求顯然也是存在的,所以從 MongoDB4.0 開始支持多文檔事務了:
- 在 MongoDB4.0 版本中,支持副本集上的多文檔事務
- 在 MongoDB4.2 版本中,新增了分片集羣上多文檔事務的支持,同時也合併了副本集上多文檔事務的支持。從 MongoDB4.2 版本開始
多文檔事務
也稱爲分佈式事務
。
在大多數情況下,多文檔事務比單文檔事務有着更大的性能開銷,所以儘可能的去優化文檔的結構,使用單文檔事務,而不是過分的依賴多文檔事務。
MongoDB 在單節點模式下是不支持事務的,所以要使用 MongoDB 的事務特性就需要搭建副本集(Replica Set
)或者分片集羣(Sharded Cluster
)
關於事務這裏簡單的介紹一下,更多內容還請參考官方文檔 https://docs.mongodb.com/v4.4/core/transactions/
六、副本集
副本集是一組維護相同數據集的 Mongod 實例,具有自動的故障恢復、讀寫分離等特點,其中包含一個主節點(Primary
)、一個或多個副本節點(Secondary
)、一個可選的仲裁節點(Arbiter
)。
- 主節點負責處理所有的寫操作,也可以處理查詢操作
- 副本節點會作從主節點同步數據,不處理寫操作,但可以通過修改客戶端連接支持讀操作來減少主節點的壓力,主節點掛掉時會參與主節點的選舉、投票
- 衝裁節點不存儲數據,不參與主節點的選舉,但是會參與投票,一般會在硬件成本有限的情況下使用仲裁節點來代替副本節點,同時也保證了副本集的正常工作。
關於副本集詳細的介紹可以參考 https://docs.mongodb.com/manual/replication/
搭建副本集可以採用 一個主節點+偶數個副本節點 或者 一個主節點+奇數個副本節點+一個仲裁節點 的方式,這裏簡單介紹在 Winddows 環境下采用1主1副本1仲裁的組合模擬搭建副本集。
這裏下載 MongoDB4.4.10 版本 zip 包,解壓3份,如下:
分別在3個根目錄下創建conf
、data\db
、log
目錄,然後在conf
、log
分別創建mongod.conf
、mongod.log
文件。
下邊是mongodb-1
中mongod.conf
的內容:
storage:
dbPath: D:\mongodb-4.4.10\mongodb-1\data\db # mongod實例的數據存儲目錄
journal:
enabled: true # 啓用持久性日誌以確保數據文件保持有效和可恢復
systemLog:
destination: file
path: D:\mongodb-4.4.10\mongodb-1\log\mongod.log # 指定日誌文件
logAppend: true # 重啓時將日誌追加到現有之日文件末尾
net:
bindIp: localhost # 綁定ip,默認就是localhost
port: 27017 # 綁定的端口號,默認就是27017
replication:
replSetName: myrs #副本集的名稱
其它兩個分別修改dbPath
、path
、port
即可。mongodb-2
、mongodb-3
的端口分別指定爲27018
、27019
配置完後,分別在bin
目下啓動3個節點:
mongod -f ../conf/mongod.conf
連接到mongodb-1
(也可以連接到其它節點,可以在bin目錄下啓動也可以配置環境變量後在任意目錄啓動),進行副本集初始化:
mongo --host localhost --port 27017
rs.initiate()
初始化成功後,mongodb-1
默認會成爲主節點,向副本集中添加副本節點mongodb-2
:
rs.add("localhost:27018")
還需要添加仲裁節點mongodb-3
:
rs.addArb("localhost:27019")
連接到上邊添加的副本節點,使其支持讀操作:
mongo --host localhost --port 27018
rs.secondaryOk()
到這裏基本的配置就完成了,向主節點添加數據後,副本節點會自動同步主節點的數據,如果主節點掛掉則會從副本節點中重新選舉新的主節點,後期重新啓動副本集的話,也會選舉新的主節點。
本文內容到這裏就結束了,下一篇我們將學習如在 Springboot 中使用 MongoDB。