MongoDB的基本使用

注意事項

  • 我們始終以下面的幾條數據爲測試用例:
"name" : "張三", "age" : "18"
"name" : "李四", "age" : "28"
"name" : "王五", "age" : "38"
  • col即爲collection,是我們創建的集合,相當於mysql中的table,我們始終以test爲集合名

一、啓動和關閉服務

// 啓動
sudo mongod
// 關閉
mongo
use admin
db.shutdownServer()

二、數據庫的使用

2.1 連接數據庫

// 連接
mongo
// 查看所有數據庫
show dbs

2.2 登錄數據庫

// 登錄賬戶
mongodb://username:password@ip
// 例如
mongodb://admin:123456@localhost/

// 登錄賬戶並使用指定數據庫
mongodb://username:password@ip/dbname
// 例如
mongodb://admin:123456@localhost/test_db

2.3 創建/刪除/選擇數據庫

// 數據庫不存在則創建數據庫,否則切換到數據庫
use test_db
// 查看當前選擇的數據庫
db
// 查看所有數據庫
show dbs
// 刪除當前數據庫
db.dropDatabase()

三、集合collection

集合相當於mysql中的數據表(table)。

  • db.createCollection(name, options)
    • name: 要創建的集合名稱
    • options: 可選參數, 指定有關內存大小及索引的選項
// 創建集合 test
db.createCollection("test") 
db.createCollection("test", { capped : true, autoIndexId : true, size : 
   6142800, max : 10000 } )
// 刪除集合test
db.test.drop()
// 查看集合
show collections

options 可以是如下參數:

字段 類型 描述
capped 布爾 (可選)如果爲 true,則創建固定集合。固定集合是指有着固定大小的集合,當達到最大值時,它會自動覆蓋最早的文檔。 當該值爲 true 時,必須指定 size 參數。
autoIndexId 布爾 (可選)如爲 true,自動在 _id 字段創建索引。默認爲 false。
size 數值 (可選)爲固定集合指定一個最大值(以字節計)。 如果 capped 爲 true,也需要指定該字段。
max 數值 (可選)指定固定集合中包含文檔的最大數量。

在 MongoDB 中,往往不需要創建集合。當插入一些文檔時,MongoDB 會自動創建集合。

db.test.insert({"name":"張三","age":18)

四、文檔document

文檔相當於mysql中數據表(table)中的行(row),對應着一條數據。

4.1 插入文檔

  • db.COLLECTION_NAME.insert(document)
db.test.insert({"name":"張三","age":18})
// 或者去掉引號
db.test.insert({name:"張三",age:18})
// 也可以先聲明document
doc = {name:"王五",age:18}
db.test.insert(doc)

// 接下來我們查詢一下
db.test.find()

4.2 更新文檔

使用 update()save() 方法來更新集合中的文檔。

4.2.1 update

update() 方法用於更新已存在的文檔。

  • db.db.collection.update(
    query,
    update,
    {
    upsert: boolean,
    multi: boolean,
    writeConcern: document
    }
    )

    參數說明:

    • query : update的查詢條件,類似sql update查詢內where後面的。
    • update : update的對象和一些更新的操作符(如,,inc…)等,也可以理解爲sql update查詢內set後面的
    • upsert : 可選,這個參數的意思是,如果不存在update的記錄,是否插入objNew,true爲插入,默認是false,不插入。
    • multi : 可選,mongodb 默認是false,只更新找到的第一條記錄,如果這個參數爲true,就把按條件查出來多條記錄全部更新。
    • writeConcern :可選,拋出異常的級別。

Demo:

我們將李四的年齡改成28

db.test.update({name:"李四"}, {$set:{age:28}})
// 只更新找到的第一條記錄
db.test.update({name:"李四"}, {$set:{age:28}},{multi:true})

4.2.2 save

save() 方法通過傳入的文檔來替換已有文檔。

  • db.collection.save(
    Document,
    {
    writeConcern: document
    }
    )

    參數說明:

    • document : 文檔數據。
    • writeConcern :可選,拋出異常的級別。

    Demo:

    我們先來查詢已存在的文檔

    db.test.find()
    

    我這裏打印出的是這些

    { "_id" : ObjectId("5d491fdcc76a65c99c61aa4f"), "name" : "張三", "age" : 18 }
    { "_id" : ObjectId("5d492019c76a65c99c61aa50"), "name" : "李四", "age" : 28 }
    { "_id" : ObjectId("5d49208ec76a65c99c61aa51"), "name" : "王五", "age" : 18 }
    

    然後我們替換王五,並把年齡改成38

    db.test.save({ "_id" : ObjectId("5d49208ec76a65c99c61aa51"), "name" : "王五", "age" : 38 })
    

    王五的整條數據就都被替換了。

    更多實例:

    // 只更新第一條記錄
    db.col.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );
    
    // 全部更新
    db.col.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );
    
    // 只添加第一條
    db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );
    
    // 全部添加進去
    db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );
    
    // 全部更新
    db.col.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );
    
    // 只更新第一條記錄
    db.col.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );
    

    4.2.3 補充

    在3.2版本開始,MongoDB提供以下更新集合文檔的方法:

    • db.collection.updateOne() 向指定集合更新單個文檔
    • db.collection.updateMany() 向指定集合更新多個文檔

    WriteConcern說明

    • WriteConcern.NONE:沒有異常拋出
    • WriteConcern.NORMAL:僅拋出網絡錯誤異常,沒有服務器錯誤異常
    • WriteConcern.SAFE:拋出網絡錯誤異常、服務器錯誤異常;並等待服務器完成寫操作。
    • WriteConcern.MAJORITY: 拋出網絡錯誤異常、服務器錯誤異常;並等待一個主服務器完成寫操作。
    • WriteConcern.FSYNC_SAFE: 拋出網絡錯誤異常、服務器錯誤異常;寫操作等待服務器將數據刷新到磁盤。
    • WriteConcern.JOURNAL_SAFE:拋出網絡錯誤異常、服務器錯誤異常;寫操作等待服務器提交到磁盤的日誌文件。
    • WriteConcern.REPLICAS_SAFE:拋出網絡錯誤異常、服務器錯誤異常;等待至少2臺服務器完成寫操作。

移除集合中的鍵值對,使用的 $unset 操作符:

db.collection.update({"_id":"56064f89ade2f21f36b03136"}, {$unset:{ "test2" : "OK"}})

4.3 刪除文檔

4.3.1 remove,已過時

remove() 方法 並不會真正釋放空間。

需要繼續執行 db.repairDatabase() 來回收磁盤空間。

  • db.collection.remove(
    query,
    justOne
    )

  • 如果你的 MongoDB 是 2.6 版本以後的,語法格式如下:

    db.collection.remove(
    query,
    {
    justOne: boolean,
    writeConcern: document

    • 參數說明:
      • query :(可選)刪除的文檔的條件。
      • justOne : (可選)如果設爲 true 或 1,則只刪除一個文檔,如果不設置該參數,或使用默認值 false,則刪除所有匹配條件的文檔。
      • writeConcern :(可選)拋出異常的級別。

Demo:

db.test.remove({'name':'王五'})

如果你想刪除所有數據

db.test.remove({})

4.3.2 deleteOne() 和 deleteMany()

這裏很簡單,對應上面的

// 刪除王五
db.test.deleteOne({'name':'王五'})
// 刪除所有叫王五的
db.test.deleteMany({'name':'王五'})
// 刪除所有數據
db.test.deleteMany({})

4.4 查詢文檔

  • db.collection.find(query, projection)
    • query :可選,使用查詢操作符指定查詢條件
    • projection :可選,使用投影操作符指定返回的鍵。查詢時返回文檔中所有鍵值, 只需省略該參數即可(默認省略)。
      • db.col.find(query, {name: 1, age: 1}) // inclusion模式 指定返回的鍵,不返回其他鍵
      • db.col.find(query, {name: 0, age: 0}) // exclusion模式 指定不返回的鍵,返回其他鍵
      • _id 鍵默認返回,需要主動指定 _id:0 纔會隱藏
      • 兩種模式不可混用
  • db.collection.find().pretty() , pretty()表示只讀查詢

示例:

// 查詢全部
db.test.find()
// 只讀查詢全部
db.test.find().pretty()
// 查詢一個
db.test.findOne()

4.4.1 MongoDB 與 RDBMS Where 語句比較

如果你熟悉常規的 SQL 數據,通過下表可以更好的理解 MongoDB 的條件語句查詢:

操作 格式 範例 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
// 查詢年齡大於20且小於30的人
db.test.find( {  age: { $gt: 20 ,$lt: 30}} )

4.4.2 And條件

  • db.col.find({key1:value1, key2:value2}).pretty()

示例:

// 查詢姓名爲 李四,年齡爲 28 的人
db.test.fins({"name":"李四", "age":"28"})

4.4.3 Or條件

OR 條件語句使用了關鍵字 $or,語法格式如下:

  • db.col.find(
    {
    $or: [
    {key1: value1}, {key2:value2}
    ]
    }
    ).pretty()

示例:

// 查詢姓名爲 李四,或者年齡爲 18 的人
db.test.find({$or:[{"name":"李四"},{"age":"18"}]})

4.4.4 And和Or的聯合使用

// 查詢年齡爲 28,且姓名爲 張三 或者 李四 的人
db.test.find({"age":"28", $or:[{"name":"張三"}, {"name":"李四"}]})

4.4.5 type操作符

我們可以通過type操作符檢索集合中匹配的數據類型

類型 數字 備註
Double 1
String 2
Object 3
Array 4
Binary data 5
Undefined 6 已廢棄。
Object id 7
Boolean 8
Date 9
Null 10
Regular Expression 11
JavaScript 13
Symbol 14
JavaScript (with scope) 15
32-bit integer 16
Timestamp 17
64-bit integer 18
Min key 255 Query with -1.
Max key 127
// 查詢所有 age 字段爲 String 的數據, 得到的是所有數據,因爲我們插入的age並不是int型,記着嗎,我們insert的時候是 "age":"xxx"
db.test.find({age:{$type:2}})
db.test.find({age:{$type:"string"}})

4.4.6 分頁查詢:Limit與Skip方法

skip和limit方法只適合小數據量分頁,如果是百萬級效率就會非常低,因爲skip方法是一條條數據數過去的,建議使用where_limit

4.4.6.1 Limit方法

如果你需要在MongoDB中讀取指定數量的數據記錄,可以使用MongoDB的Limit方法,limit()方法接受一個數字參數,該參數指定從MongoDB中讀取的記錄條數。

  • db.col.find().limit(num)
4.4.6.2 Skip()方法

我們除了可以使用limit()方法來讀取指定數量的數據外,還可以使用skip()方法來跳過指定數量的數據,skip方法同樣接受一個數字參數作爲跳過的記錄條數。

  • db.col.find().limit(num).skip(num)
// 從第10調開始讀取100條
db.col.find().skip(10).limit(100)
// 下面的會跳過 張三, 只顯示一條 李四
db.test.find().limit(1).skip(1)

4.4.7 排序

使用 sort() 方法對數據進行排序,sort() 方法可以通過參數指定排序的字段,並使用 1 和 -1 來指定排序的方式,其中 1 爲升序排列,而 -1 是用於降序排列。

  • db.col.find().sort({key:1})
// 根據 age 字段降序排列,現實的順序爲 王五 李四 張三
db.test.find().sort({age:-1})

4.4.8 索引

使用 createIndex() 方法來創建索引。

注意在 3.0.0 版本前創建索引方法爲 db.collection.ensureIndex(),之後的版本使用了 db.collection.createIndex() 方法,ensureIndex() 還能用,但只是 createIndex() 的別名。

  • db.collection.createIndex(keys, options)
// 1 爲指定按升序創建索引,如果你想按降序來創建索引指定爲 -1 即可
db.test.createIndex({"age":1})

createIndex() 方法中你也可以設置使用多個字段創建索引(關係型數據庫中稱作複合索引)。

db.test.createIndex({"age":1,"name":-1})

createIndex() 接收可選參數,可選參數列表如下:

Parameter Type Description
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.test.createIndex({name: 1, age: 1}, {background: true})
  • 查看集合索引
db.col.getIndexes()
  • 查看集合索引大小
db.col.totalIndexSize()
  • 刪除集合所有索引
db.col.dropIndexes()
  • 刪除集合指定索引
db.col.dropIndex("索引名稱")

4.4.9 聚合

聚合主要用於處理數據(諸如統計平均值,求和等),並返回計算後的數據結果。有點類似sql語句中的 count(*)。

  • db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

示例:

假設我們現在有四條數據:

{ "_id" : ObjectId("5d522cd625e9232e10114e20"), "name" : "張三", "age" : 18, "like" : 100 }
{ "_id" : ObjectId("5d522cde25e9232e10114e21"), "name" : "李四", "age" : 28, "like" : 150 }
{ "_id" : ObjectId("5d522ce625e9232e10114e22"), "name" : "王五", "age" : 38, "like" : 200 }
{ "_id" : ObjectId("5d5252242825b2cef2d05dd3"), "name" : "趙六", "age" : 48, "like" : 200 }

執行:

// 以like分組,並且求like字段相同的人數總和
// 相當於 select like as _id, count(*) as total from test group by like;
db.test.aggregate([{$group: {_id:"$like", total:{$sum: 1}}}])

// log
{ "_id" : 200, "total" : 2 }
{ "_id" : 150, "total" : 1 }
{ "_id" : 100, "total" : 1 }

執行:

// 以like分組,並且求like字段相同的年齡的平均值
db.test.aggregate({$group: {_id:"$like", avg_age:{$avg:"$age"}} })

// log
{ "_id" : 200, "avg_age" : 43 }
{ "_id" : 150, "avg_age" : 28 }
{ "_id" : 100, "avg_age" : 18 }

4.4.10 管道

管道在Unix和Linux中一般用於將當前命令的輸出結果作爲下一個命令的參數。

MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢後將結果傳遞給下一個管道處理。管道操作是可以重複的。

表達式:處理輸入文檔並輸出。表達式是無狀態的,只能用於計算當前聚合管道的文檔,不能處理其它的文檔。

這裏我們介紹一下聚合框架中常用的幾個操作:

  • $project:修改輸入文檔的結構。可以用來重命名、增加或刪除域,也可以用於創建計算結果以及嵌套文檔。
  • $match:用於過濾數據,只輸出符合條件的文檔。$match使用MongoDB的標準查詢操作。
  • $limit:用來限制MongoDB聚合管道返回的文檔數。
  • $skip:在聚合管道中跳過指定數量的文檔,並返回餘下的文檔。
  • $unwind:將文檔中的某一個數組類型字段拆分成多條,每條包含數組中的一個值。
  • $group:將集合中的文檔分組,可用於統計結果。
  • $sort:將輸入文檔排序後輸出。
  • $geoNear:輸出接近某一地理位置的有序文檔。
4.4.10.1 $project

用來控制顯示的字段

// 下面的兩個查詢結果是相等的,都只查詢出那麼和age字段,其他的字段不會查詢
db.test.aggregate({$project:{name:1,age:1}})
db.test.find({},{like:1,age:1})
4.4.10.11 $match
// 查詢like大於100且小於200的數據
db.test.aggregate({$match:{like:{$gt:100,$lt:200}}})
// 查詢like大於100且小於200的數據,後將符合條件的記錄送到下一階段$group管道操作符進行處理(將查詢到的數據不分組,顯示總數)
db.test.aggregate([{$match:{like:{$gt:100,$lt:300}}}, {$group:{_id:null,count:{$sum:1}} }])

//log
{ "_id" : null, "count" : 3 }
// 查詢like大於100且小於200的數據,後將符合條件的記錄送到下一階段$group管道操作符進行處理(將查詢到的數據按姓名分組,顯示每組總數)
db.test.aggregate([{$match:{like:{$gt:100,$lt:300}}}, {$group:{_id:null,count:{$sum:1}} }])

//log
{ "_id" : "趙六", "count" : 1 }
{ "_id" : "王五", "count" : 1 }
{ "_id" : "李四", "count" : 1 }
4.4.10.12 $skip
db.test.aggregate({ $skip : 5 });

五、DB 複製(副本集)

MongoDB複製是將數據同步在多個服務器的過程。

複製提供了數據的冗餘備份,並在多個服務器上存儲數據副本,提高了數據的可用性, 並可以保證數據的安全性。

複製還允許您從硬件故障和服務中斷中恢復數據。

在本教程中我們使用同一個MongoDB來做MongoDB主從的實驗, 操作步驟如下:

1、關閉正在運行的MongoDB服務器。

現在我們通過指定 --replSet 選項來啓動mongoDB。–replSet 基本語法格式如下:

mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"

實例

mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0

以上實例會啓動一個名爲rs0的MongoDB實例,其端口號爲27017。

啓動後打開命令提示框並連接上mongoDB服務。

在Mongo客戶端使用命令rs.initiate()來啓動一個新的副本集。

我們可以使用rs.conf()來查看副本集的配置

查看副本集狀態使用 rs.status() 命令


副本集添加成員

添加副本集的成員,我們需要使用多臺服務器來啓動mongo服務。進入Mongo客戶端,並使用rs.add()方法來添加副本集的成員。

語法

rs.add() 命令基本語法格式如下:

>rs.add(HOST_NAME:PORT)

實例

假設你已經啓動了一個名爲mongod1.net,端口號爲27017的Mongo服務。 在客戶端命令窗口使用rs.add() 命令將其添加到副本集中,命令如下所示:

>rs.add("mongod1.net:27017")
>

MongoDB中你只能通過主節點將Mongo服務添加到副本集中, 判斷當前運行的Mongo服務是否爲主節點可以使用命令db.isMaster() 。

MongoDB的副本集與我們常見的主從有所不同,主從在主機宕機後所有服務將停止,而副本集在主機宕機後,副本會接管主節點成爲主節點,不會出現宕機的情況。

六、分片

分片

在Mongodb裏面存在另一種集羣,就是分片技術,可以滿足MongoDB數據量大量增長的需求。

當MongoDB存儲海量的數據時,一臺機器可能不足以存儲數據,也可能不足以提供可接受的讀寫吞吐量。這時,我們就可以通過在多臺機器上分割數據,使得數據庫系統能存儲和處理更多的數據。


爲什麼使用分片

  • 複製所有的寫入操作到主節點
  • 延遲的敏感數據會在主節點查詢
  • 單個副本集限制在12個節點
  • 當請求量巨大時會出現內存不足。
  • 本地磁盤不足
  • 垂直擴展價格昂貴

MongoDB分片

下圖展示了在MongoDB中使用分片集羣結構分佈:

img

上圖中主要有如下所述三個主要組件:

  • Shard:

    用於存儲實際的數據塊,實際生產環境中一個shard server角色可由幾臺機器組個一個replica set承擔,防止主機單點故障

  • Config Server:

    mongod實例,存儲了整個 ClusterMetadata,其中包括 chunk信息。

  • Query Routers:

    前端路由,客戶端由此接入,且讓整個集羣看上去像單一數據庫,前端應用可以透明使用。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章