簡明 MongoDB 入門教程

MongoDB 是免費開源的跨平臺 NoSQL 數據庫,命名源於英文單詞 humongous,意思是「巨大無比」,可見開發組對 MongoDB 的定位。與關係型數據庫不一樣,MongoDB 的數據以相似於 JSON 格式的二進制文檔存儲:mongodb

{
    name: "Angeladady",
    age: 18,
    hobbies: ["Steam", "Guitar"]
}

文檔型的數據存儲方式有幾個重要好處:文檔的數據類型能夠對應到語言的數據類型,如數組類型(Array)和對象類型(Object);文檔能夠嵌套,有時關係型數據庫涉及幾個表的操做,在 MongoDB 中一次就能完成,能夠減小昂貴的鏈接花銷;文檔不對數據結構加以限制,不一樣的數據結構能夠存儲在同一張表。shell

MongoDB 的文檔數據模型和索引系統能有效提高數據庫性能;複製集功能提供數據冗餘,自動化容災容錯,提高數據庫可用性;分片技術可以分散單服務器的讀寫壓力,提升併發能力,提高數據庫的可拓展性。MongoDB 高性能,高可用性、可擴展性等特色,使其至 2009 年發佈以來,逐漸被承認,並被愈來愈多的用於生產環境中。AWS、GCP、阿里雲等雲平臺都提供了十分便捷的 MongoDB 雲服務。數據庫

開啓 MongoDB 之旅

第一步,安裝 MongoDB。到官網下載壓縮包或安裝包,解壓或安裝後,能夠把 bin 目錄添加到環境變量,方便後續命令的執行。在開始階段,要用到 mongo 和 mongod 兩個命令。文章示例以 Linux 爲標準。segmentfault

啓動實例

第二步,經過 mongod 命令啓動實例。啓動以前,新建一個目錄來存放 mongoDB 的數據和日誌:數組

mkdir mongoDB_example
cd mongoDB_example
mkdir bin data conf log
touch log/mongodb.log

上面的命令建立了四個目錄:安全

  • bin 若是不打算把 mongodb 的命令放到環境變量,能夠將經常使用命令複製到 bin 目錄,方便調用,如 mongo 和 mongod。也能夠把編寫的腳本,如副本集的啓動腳本,放在 bin 目錄裏服務器

  • data 用來存放數據數據結構

  • log 用來存放日誌文件併發

  • conf 用來存放配置文件高併發

在項目目錄中,使用 mongod 命令來啓動 mongoDB 進程:

mongod --fork --port 12345 --dbpath data\db  --logpath log/mongodb.log

上面命令中選項的意義:

  • port 指定端口

  • dbpath 指定數據存放路徑

  • logpath 指定日誌存放路徑

  • fork 後臺運行(退出 shell 後進程不會被中斷了)

啓動順利的話,就能夠輸入ps aux | grep mongod,查看到啓動的 mongod 實例。若是啓動沒有成功,最好先檢查下路徑設置和端口占用。

配置文件啓動實例

相比設定選項來啓動實例,經過配置文件啓動更具備可維護性。在 conf 目錄下新建一個配置文件:

vi conf/mongodb.conf

配置文件使用<option> = <value>的格式。接下來,把剛纔的啓動配置輸入到配置文件中:

port = 12345
dbpath = data
logpath = log/mongodb.log
fork = true

啓動以前別忘了先殺掉以前啓動的實例kill -2 <pid>,而後再從新啓動 mongoDB:

mongod -f conf/mongodb.conf

在沒有指定接口時,默認啓動在 27017 端口。在配置的時候使用絕對路徑替代相對路徑,有利於在排查故障時查找 mongoDB 進程啓動的目錄。

鏈接實例

第三步,經過 mongo 命令來鏈接 mongoDB 實例:

mongo [options] [db address] [file names]

以前啓動實例的是在本地 12345 端口,安全模式未被開啓,因此不須要輸入用戶名和密碼便可直接鏈接:

mongo 127.0.0.1:12345

或者經過--host--port選項指定主機和端口。一切順利的話,就進入了 mongoDB shell,shell 會報出一連串權限警告,不過不用擔憂,這並不會影響以後的操做。在添加受權用戶和開啓認證後,這些警告會自動消失。

數據庫 CRUD 操做

在進行增查改刪操做以前,先了解下經常使用的 shell 操做:

  • db 顯示當前所在數據庫,默認爲 test

  • show dbs 列出可用數據庫

  • show tables show collections 列出數據庫中可用集合

  • use <database> 用於切換數據庫

mongoDB 預設有兩個數據庫,admin 和 local,admin 用來存放系統數據,local 用來存放該實例數據,在副本集中,一個實例的 local 數據庫對於其它實例是不可見的。使用 use 命令切換數據庫:

> use admin
> use local
> use newDatabase

能夠 use 一個不存在的數據庫,當你存入新數據時,mongoDB 會建立這個數據庫:

> use newDatabase
> db.newCollection.insert({x:1})
WriteResult({ "nInserted" : 1 })

以上命令向數據庫中插入一個文檔,返回 1 表示插入成功,mongoDB 自動建立 newCollection 集合和數據庫 newDatabase。下面將建立一個 drivers 集合,進行增查改刪操做。

建立(Create)

MongoDB 提供 insert 方法建立新文檔:

  • db.collection.inserOne() 插入單個文檔
    WriteResult({ "nInserted" : 1 })

  • db.collection.inserMany() 插入多個文檔

  • db.collection.insert() 插入單條或多條文檔

這裏以 insert 方法爲例:

> db.drivers.insert({name:"Chen1fa",age:18})
> db.drivers.insert({name:"Xiaose",age:35})
> db.drivers.insert({_id:91,name:"Sun1feng",age:34})

要注意,age:18age:"18"是不同的,前者插入的是數值,後者插入的是字符串。插入新文檔若是未指定 _id,mongoDB 會自動爲插入的文檔添加 _id 字段。使用 db.dirvers.find() 命令便可看到剛剛插入的文檔:

> db.dirvers.find()
{ "_id" : ObjectId("598964bd56b8c69ae1e5f36a"), "name" : "Chen1fa", "age" : 18 }
{ "_id" : ObjectId("598964d456b8c69ae1e5f36b"), "name" : "Xiaose", "age" : 35 }
{ "_id" : 91, "name" : "Sun1feng", "age" : 34 }

查找(Read)

MongoDB 提供 find 方法查找文檔,第一個參數爲查詢條件:

> db.drivers.find() #查找全部文檔
{ "_id" : ObjectId("598964bd56b8c69ae1e5f36a"), "name" : "Chen1fa", "age" : 18 }
{ "_id" : ObjectId("598964d456b8c69ae1e5f36b"), "name" : "Xiaose", "age" : 35 }
{ "_id" : 91, "name" : "Sun1feng", "age" : 34 }

> db.drivers.find({name: "Xiaose"}) #查找 name 爲 Xiaose 的文檔
{ "_id" : ObjectId("598964d456b8c69ae1e5f36b"), "name" : "Xiaose", "age" : 35 }

> db.drivers.find({age:{$gt:20}}) #查找 age 大於 20 的文檔
{ "_id" : ObjectId("598964d456b8c69ae1e5f36b"), "name" : "Xiaose", "age" : 35 }
{ "_id" : 91, "name" : "Sun1feng", "age" : 34 }

上述代碼中的$gt對應於大於號>的轉義。第二個參數能夠傳入投影(projection,投影儀中,白色光源經過分光鏡、液晶板、投影鏡頭的光學變換後,投射到反射面上,顯示出了彩色圖像)文檔映射數據:

> db.drivers.find({age:{$gt:20}},{name:1})
{ "_id" : ObjectId("598964d456b8c69ae1e5f36b"), "name" : "Xiaose" }
{ "_id" : 91, "name" : "Sun1feng" }

上述命令將查找 age 大於 20 的文檔,返回 name 字段,排除其它字段。投影文檔中字段爲 1 或真值表示包含,0 或假值表示排除,能夠設置多個字段爲 1 或 0,但不能混合使用。

除此以外,還能夠經過 count、skip、limit 等指針(Cursor)方法,改變文檔查詢的執行方式:

> db.drivers.find().count() #統計查詢文檔數目
3
> db.drivers.find().skip(1).limit(10).sort({age:1})
{ "_id" : 91, "name" : "Sun1feng", "age" : 34 }
{ "_id" : ObjectId("598964d456b8c69ae1e5f36b"), "name" : "Xiaose", "age" : 35 }

上述查找命令跳過 1 個文檔,限制輸出 10 個,以 name 子段正序排序(大於 0 爲正序,小於 0 位反序)輸出結果。最後,可使用 Cursor 方法中的 pretty 方法,提高查詢文檔的易讀性,特別是在查看嵌套的文檔和配置文件的時候:

> db.drivers.find().pretty()

更新(Update)

MongoDB 提供 updata 方法更新文檔:

  • db.collection.updateOne() 更新最多一個符合條件的文檔

  • db.collection.updateMany() 更新全部符合條件的文檔

  • db.collection.replaceOne() 替代最多一個符合條件的文檔

  • db.collection.update() 默認更新一個文檔,可配置 multi 參數,跟新多個文檔

以 update() 方法爲例。其格式:

> db.collection.update(
    <query>,
    <update>,
    {
        upsert: <boolean>,
        multi: <boolean>
    }
)

各參數意義:

  • query 爲查詢條件

  • update 爲修改的文檔

  • upsert 爲真,查詢爲空時插入文檔

  • multi 爲真,更新全部符合條件的文檔

下面的命令將 name 字段爲 Chen1fa 的文檔,更新 age 字段爲 30:

> db.drivers.update({name:"Chen1fa"},{name:"Chen1fa", age:30})

要注意的是,若是更新文檔只傳入 age 字段,那麼文檔會被更新爲{age: 30},而不是{name:"Chen1fa", age:30}。要避免文檔被覆蓋,須要用到 $set 指令,$set 僅替換或添加指定字段:

> db.drivers.update({name:"Chen1fa"},{$set:{age:30}})

若是要在查詢的文檔不存在的時候插入文檔,要把 upsert 參數設置真值:

> db.drivers.update({name:"Alen"},{age:24},{upsert: true})

update 方法默認狀況只更新一個文檔,若是要更新符合條件的全部文檔,要把 multi 設爲真值,並使用 $set 指令:

> db.drivers.update({age:{$gt:25}},{$set:{license:'A'}},{multi: true})
> db.drivers.update({age:{$lt:25}},{$set:{license:'C'}},{multi: true})

最終結果:

> db.dirvers.find()
{ "_id" : ObjectId("598964bd56b8c69ae1e5f36a"), "name" : "Chen1fa", "age" : 30, "license" : "A" }
{ "_id" : ObjectId("598964d456b8c69ae1e5f36b"), "name" : "Xiaose", "age" : 35, "license" : "A" }
{ "_id" : 91, "name" : "Sun1feng", "age" : 34, "license" : "A" }
{ "_id" : ObjectId("598968b3ed1eccef17e79abe"), "age" : 24, "license" : "C" }

刪除(Delete)

MongoDB 提供了 delete 方法刪除文檔:

  • db.collection.deleteOne() 刪除最多一個符合條件的文檔

  • db.collection.deleteMany() 刪除全部符合條件的文檔

  • db.collection.remove() 刪除一個或多個文檔

以 remove 方法爲例:

> db.drivers.remove({name:"Xiaose"}) #刪除全部 name 爲 Xiaose 的文檔
> db.drivers.remove({age:{$gt:30}},{justOne:true}) #刪除全部 age 大於 30 的文檔
> db.drivers.find()
{ "_id" : ObjectId("598964bd56b8c69ae1e5f36a"), "name" : "Chen1fa", "age" : 30, "license" : "A" }
{ "_id" : ObjectId("598968b3ed1eccef17e79abe"), "age" : 24, "license" : "C" }

MongoDB 提供了 drop 方法刪除集合,返回 true 表面刪除集合成功:

> db.drivers.drop()

後話

相比傳統關係型數據庫,MongoDB 的 CURD 操做更像是編寫程序,更符合開發人員的直覺,不過 MongoDB 一樣也支持 SQL 語言。MongoDB 的 CURD 引擎配合索引技術、數據聚合技術和 JavaScript 引擎,賦予 MongoDB 用戶更強大的操縱數據的能力。

關閉實例

關閉 mongoDB 服務:

> use admin
> db.shutdownServer()

使用 exit 或 Ctrl + C 斷開鏈接:

> exit

結語

上述,咱們啓動了一個不安全的 MongoDB 實例,應用到生產環境中,還須要瞭解 MongoDB 的安全機制,瞭解如何創建索引提高數據庫的讀寫速度。隨着數據的增加,須要瞭解副本集技術如何將多個實例部署到不一樣的服務器、瞭解分片技術對數據庫進行橫向擴展。爲保證服務器性能和安全,須要瞭解如何對 MongoDB 進行測試和監控…

「冰封三尺,非一日之寒」,一樣,要想徹底掌握 MongoDB 還有很長的路要走。願戒驕戒躁,在學習的路上,與君共勉。

參考

相關文章
相關標籤/搜索