[Mongo] MongoDB Shell 指令操作(Shell CLI)
# 啟動 MongoDB Shell
$ mongosh
# 查看指令
> help # 檢視和 shell 有關的指令
> db.help() # 檢視和 db 有關的指令
> db.[collection].help() # 檢視和 collections 有關的指令
基本觀念
-
NoSQL: not only SQL
-
階層關係:
- database:在 MongoDB server 中可以有多個 database(DB)
- collection: 用來整理組織 document,類似 SQL 中的 table。一個 db 中可以有多個 collections。
- document: 個別的紀錄(record),類似 SQL 中的 row。一個 collections 中可以有多個 documents
- collection: 用來整理組織 document,類似 SQL 中的 table。一個 db 中可以有多個 collections。
- database:在 MongoDB server 中可以有多個 database(DB)
-
MongoDB 將資料儲存成 BSON 的文件,BSON 是一種以二進位(binary)方式來表徵 JSON 的方法
- 在操作 MongoDB 時,我們提供的是 JSON,MongoDB 的 drivers 會把這個 JSON 轉成對應的 BSON 在保存在 MongoDB 中
- BSON 可以包含比 JSON 更多的資料類型
- BSON 的儲存效率更高
-
MongoDB 的原子性(Atomicity)是建立在 Document Level,也就是說,一個 Document 要嘛有被完整保存成功,要嘛失敗完全沒存,不會有只存了「部分 Document」的情況。
當你使用 insertMany()
或 updateMany()
這類方法一次改動多個 documents 時,是可能會發生部分失敗的情況。但要留意的是,這裡的部分失敗指的是這個「操作」,而不是「document」。如果需要確保整個操作的原子性,需要使用 transaction。
基本指令
> help # 檢視常用指令
> show dbs # 檢視目前所有的 database
> show collections # 檢視當前 db 有的 collections
> db # 顯示當前所在資料庫
> quit # 離開
資料庫相關
db # 顯示當前所在資料庫
show dbs # 顯示現有資料庫(database)
show collections # 顯示當前資料庫內所有的 collections
use [DatabaseName] # 使用此資料庫,如果該資料庫不存在則自動「建立」並使用
##
# 針對 database
##
db.getCollectionNames() # 顯示當前資料庫中的 collection 名稱
db.dropDatabase() # 刪除資料庫
##
# 針對 collection
##
db.myCollection.drop() # 刪除 myCollection 這個 collection
- 在 MongoDB 中,如果該 database 不存在,MongoDB 會在第一次儲存資料到該 database 時建 立該 database。
CREATE
##
# Create
# db.collection.insertOne({})
# db.collection.insertMany([{}, {}])
##
db.todos.insertOne({ title: 'Hello Mongo' }); # 建立 document
Ordered Behavior
預設的情況下,MongoDB 使用的是 ordered behavior,在新增資料時如果發生錯誤(例如,duplicate key error):
- 它不會有 rollback 的行為,成功寫進去的資料不會因為其中一個資料寫不進去而被還原
- 預設當
ordered
是true
時,一旦發生錯誤,在錯誤發生後的資料就不會繼續寫入。如果希望它能夠忽略掉這個錯誤,繼續寫入後面的資料,則可以把orderer
設成false
db.hobbies.insertMany(
[
{
_id: 'hiking',
name: 'hiking',
},
{
_id: 'yoga',
name: 'yoga',
},
{
_id: 'cooking',
name: 'cooking',
},
],
{ ordered: false },
);
Write Concern
Write Concern 的目的是確保 MongoDB 對寫操作的確認程度(acknowledgement level)。它允許用戶指定在寫操作被認為成功之前,MongoDB 必須接收到的確認數量。這可以確保數據的耐久性(durability)和一致性(availability),例如在單一伺服器、複寫集(replica sets)或分片集群(shared clusters)中,提供不同程度的數據安全保障。較高的 Write Concern 能增加數據安全性,但可能會降低效能。
如同這張圖所示:
MongoDB 在把資料寫進資料庫時,為了效能,實際上還有一個 Memory 存在;另外,需要的話,還可以寫一個實體的 Journal 檔,如此,一旦資料庫發生錯誤,只要有寫了 Journal 檔,還是可以把沒有寫入到資料庫中的資料復原。
透過 Write Concern 就可以設定這個行為:
{ w: <value>, j: <boolean>, wtimeout: <number> }
w
- Durability:預設的情況下是
w: majority
,表示大部分的 replica set 需要確認完成寫的東西後,才算成功。當資料是不可遺失的話,可以設定更高的 write concerns。 - Performance:如果你的使用情境非常重視寫入的效能,並且能夠容忍可能的資料流失,則可以把 write concern 設成
w: 1
或w: 0
。
- Durability:預設的情況下是
j
:用於指定寫操作在資料寫入日誌(journal)後才會得到確認(acknowledge)。日誌是一種預寫日誌(write-ahead log),用來確保在錯誤發生時數據的完整性- 當
j
是true
時,表示 MongoDB 確保寫操作只有在數據成功寫入日誌(on-disk journal)後才會被確認,但相對的會犧牲效能
- 當
wtimeout
:單位是 ms,目的是避免w
設定的節點無限期等待
當使用情境不同的,例如在 Standalone 或 Replica Sets 時,w
和 j
會有不同的行為,詳細可以參考官方文件的說明。
不等待資料是否寫進 memory 中:
db.hobbies.insertOne('writing', { writeConcern: { w: 1, j: true, wtimeout: 200 } });
// {
// acknowledged: false,
// insertedId: ObjectId('66782454b1ed5d2a0fbe0dce')
// }
READ
keywords: find()
, findOne()
, count()
, distinct()
/**
* Read
* db.collection.find()
* db.collection.findOne()
* db.collection.countDocuments()
* db.collection.estimatedDocumentCount()
* db.collection.distinct()
*/
db.todos.countDocuments(); // todos 中有多少 documents
db.todos.estimatedDocumentCount();
db.todos.find(); // 檢視某一 Collections 內所有的 documents
db.todos.find({ title: 'Create new Node course' }); // 檢視特定 document
db.todos.find({ _id: ObjectId('5c0beffdeb866557d13c0ef8') }); // 檢視特定 document
db.todos.find().pretty(); // 以格式化的方式列出 document
db.todos.find().limit(2); // 指列出前兩筆 document
db.todos.find().skip(2); // 忽略前兩筆資料
db.todos.find().sort({ title: 1 }); // 排序資料,1 是 ascending,-1 是 descending
db.todos.find().toArray();
db.todos.find().forEach();
Basic Query
Query Embedded Documents (Nested Object)
可以在 key 的地方使用 "x.y.z"
, 就可以搜尋 embedded documents(nested objects)
db.todos.find({ 'status.description': 'on-time' });
db.movies.find({ 'rating.average': { $gte: 6.7 } });
Query Elements in an Array
如果要找的是 array 中的元素:
// Query 尋找陣列中的資料
// 假設 hobbies 是 array,我們想要找 hobbies 中包含 'sports' 的 document
// hobbies: ['sports', 'video game']
db.todos.find({ hobbies: 'sports' });
上面的 query 會找到在陣列中「包含」有該元素的資料,如果你想要找到是在該陣列中「只有那個元素」,則要使用 hobbies: ["sports"]
。
如果 array 中的元素是 array of object,例如:
# history: [
# { disease: 'headache', treatment: 'aspirin' },
# { disease: 'fever', treatment: 'ibuprofen' }
# ]
如果我們希望找到 history 中有 disease 是 'headache'
的元素,可以使用:
db.patientData.find({ 'history.disease': 'headache' });
當如果你希望找到的是 history
中有完全相同的物件,則是使用:
// 可以用類似的方式來 query
db.patientData.find({ history: { disease: 'headache', treatment: 'aspirin' } });
Array Query Operator
$elemMatch
假設想要找出在 hobbies
array 中,有 { title: 'Sports' }
,且 { frequency: value }
的 value
大於等於 3 的元素。
如果我們使用 $and
並不能得到我們想要的結果:
db.users.find({
// 這個 query 會找到 hobbies 陣列中有 title 為 Sports 且 frequency 大於等於 3 的 documents
// 但不表示這個條件會在同一個 element 中同時被滿足,舉例來說,以下的文件就會被找到
// { hobbies: [{ title: 'Sports', frequency: 2}, { title: 'Yoga', frequency: 3 }] }
$and: [{ 'hobbies.title': 'Sports' }, { 'hobbies.frequency': { $gte: 3 } }],
});