MongoDB 簡介
Understanding Databases, Collections & Documents
MongoDB Server > Databases > Collections > Documents
在 MongoDB 的伺服器中,每個使用者可以建立多個 Database,每個 Database 裡可以有多個 Collection,
每個 Collection 裡可以有多個 Document。
- Collection 好比 RDBMS 的 Table
- Document 好比 RDBMS 的 Record
Creating Databases & Collections
mongosh 指令複習
- $ show dbs
- $ use DB_NAME
- $ db.COLLECTION_NAME.insertOne({ YOUR_DOCUMENT })
Understanding JSON Data
以下範例相當於一個 JSON 檔內儲存兩筆 MongoDB Document,亦即一對花括號僅容納一筆 Document。
由 line 5 ~ 7 可知,Document 可以儲存多種資料型別。
[
{
"departureAirport": "MUC",
"arrivalAirport": "SFO",
"aircraft": "Airbus A380",
"distance": 12000,
"intercontinental": true
},
{
"departureAirport": "LHR",
"arrivalAirport": "TXL",
"aircraft": "Airbus A320",
"distance": 950,
"intercontinental": false
}
]
Comparing JSON & BSON
在 MongoDB 的 Collection 當中成功插入 Document 後,該筆 Document 會自動附帶結構如下的鍵值對。
其中 ObjectId 是 BSON 格式獨特的資料型別。
"_id": ObjectId("4j5i0gja;k...")
雖然 MongoDB 會自動產生 Document ID,但開發者仍可手動輸入 ID,但該鍵值對的鍵名稱必須是「_id」, 其值則可以是。
db.collection_name.insertOne({insert:"manual", _id: "RX-78-2"})
db.collection_name.insertOne({_id: 3.141, sign: "pi"})
在 RDBMS 資料庫中,同一 Table 的 Record 必須擁有相同的資料結構(Schema)
在 MongoDB,同一 Collection 的 Document 可以擁有不同的資料結構。
[
{
_id: ObjectId("646f0fd133e3ab77e3a6f3da"),
departureAirport: 'MUC',
arrivalAirport: 'SFO',
aircraft: 'Airbus A380',
distance: 12000,
intercontinental: true
},
{
_id: ObjectId("646f13c633e3ab77e3a6f3db"),
name: 'try',
schema: 'free',
value: 123,
validate: false
}
]
Create, Read, Update, Delete (CRUD) & MongoDB
Create
- insertOne(data, options)
- insertMany(data, options)
Read
- find(filter, options)
- findOne(filter, options)
update
- updateOne(filter, data, options)
- updateMany(filter, data, options)
- replaceOne(filter, data, options)
update
- deleteOne(filter, options)
- deleteMany(filter, options)
Finding, Inserting, Deleting & Updating Elements
- updateOne(filter, data, options)
更新符合 filter 的 Document,在 Document 中 新增或更改 data 中的鍵值對。
db.collection_name.updateOne({key1: value1}, {$set: {key2: value2}})
- updateMany(filter, data, options)
更新符合 filter 的 Document,在 Document 中 新增或更改 data 中的鍵值對。
當 filter 指定為 {} 時,表示以 Collection 內的所有 Document 為更新對象。
db.collection_name.updateMany({}, {$set: {key1: value1}})
- deleteOne(filter, options)
刪除符合 filter 的單筆 Document
db.collection_name.deleteOne({key1: value1})
- deleteMany(filter, options)
刪除符合 filter 的所有 Document
當 filter 指定為 {} 時,表示刪除 Collection 內的所有 Document
db.collection_name.deleteMany({key1: value1})
Understanding "insertMany()"
- insertMany(data, options)
在 Collection 中插入 data。在 mongosh 當中操作時,
可直接以 [{data1}, {data2}, ...] 的格式貼上,但必須在貼上後才輸入閉括號。
db.collection_name.insertMany([{key1: value1}, {key2: value2}, ...])
Diving Deeper Into Finding Data
- find(filter, options) 從 Collection 中找出符合 filter 的 Document。 可不傳入 fliter,如此可找出 Collection 中的所有 Document。 可搭配運算子($gt, )縮小查詢範圍。
db.collection_name.find()
db.collection_name.find({key1: value1})
db.flights.find({key1: {$gt: value}})
前往官方文件檢視其他運算子: Query and Projection Operators
- findOne(filter, options) 從 Collection 中找出符合 filter 的第一筆 Document。
db.collection_name.findOne({key1: {$lte: value}})
"update" vs "updateMany()"
- update(filter, data, options)
本函式於 2023/5/25 時已棄用。欲覆蓋既有 data,可使用 replaceOne。
本函式不需搭配 $set 運算子,且傳入函式的 data 會取代原始 data。 - updateOne(filter, data, options)
本函式需搭配 $set 運算子,傳入函式的 data 不會取代原始 data。 - updateMany(filter, data, options)
本函式需搭配 $set 運算子,傳入函式的 data 不會取代原始 data。
Understanding "find()" & the Cursor Object
find() 並非回傳所有 Document,而是回傳一個 Cursor Object,
倘若 find() 找到超過 20 筆資料,第 21 筆起不會直接顯示於終端機。
- find().toArray()
可將 Cursor Object 轉換為陣列,如此即使資料超過 20 筆也會全部顯示。 - find().froEach()
不同的語言有不同的語法,詳見官方文件
將匿名函式傳入 forEach(),可迭代處理 Cursor Object。
db.collection_name.find()
.forEach((value) => {printjson(value._id)})
Understanding Projection
假設有一筆 Document 如下。使用 find() 讀取這筆 Document 時,
若未輸入任何選項將回傳五個鍵值對(不含 _id)。
反之,查詢時加入選項可即可取得指定的鍵值對,此概念稱為 Projection。
{
"fieldName1": "value1",
"fieldName2": "value2",
"fieldName3": "value3",
"fieldName4": "value4",
"fieldName5": "value5"
}
以下為 Projection 範例,第一個指令會取回 key1 的鍵值對及 _id;
第二個指令僅取回 key1 的鍵值對。可知查詢條件中的值 1 表 true,0 表 false。
$ db.collection_name.find({}, {key1: 1})
$ db.collection_name.find({}, {key1: 1, _id: 0})
Embedded Documents & Arrays - The Theory
- Embedded Documents
以巢狀結構儲存資料,最高可達 100 層,容量上限為每筆 Document 16 MB。 - Arrays Document 可藉由 Array 儲存列表,也可在巢狀結構中嵌入 Array。
Working with Arrays
Document 的鍵值對中,值可以是 Array,而 Array 當中可以儲存各種型別的資料。
以下範例中,Array 儲存了四個元素,分別為字串、整數、布林值、Document
$ db.collection_name.updateOne({key1: value1},
{$set: {key2: ["string", 1, true, {}]}})
Accessing Structured Data
// 從 Collection 當中找出一筆符合條件的資料,且僅回傳 key2 的值。
$ db.collection_name.findOne({key1: value1}).key2
// 適用於目標為 Array 時。從 Collection 當中找出一筆符合條件的資料,
且僅回傳 key2 的值的索引值為 1 的元素。
$ db.collection_name.findOne({key1: value1}).key2[1]
// 輸入查詢條件時,冒號前的部分用 " 夾住,表示以嵌入式結構為條件查詢。
$ db.collection_name.find({"key.embeddedKey": "value"})
Time to Practice - The Basics & CRUD Operations
{
"firstName": "Max",
"lastName": "Schwarzmueller",
"age": 29,
"history": [
{"disease": "cold", "treatment": "..."},
{ ... }
]
}
- Insert 3 patient records with at least 1 history entry per patient
- Update patient data of 1 patient with new age, name and history entry
- Find all patients who are older than 30 (or a value of your choice)
- Delete all patients who got a cold as a disease
2023/5/25 練習記錄
- 先建立新資料庫
$ use patients
- 編寫 JSON 資料
[
{
"firstName": "Max",
"lastName": "Schwarzmueller",
"age": 29,
"history": [
{"disease": "cold", "treatment": "treatment2"},
{"disease": "COVID-19", "treatment": "treatment1" }
]
},
{
"firstName": "小明",
"lastName": "王",
"age": 39,
"history": [
{"disease": "cold", "treatment": "treatment2"},
{"disease": "COVID-19", "treatment": "treatment1" },
{"disease": "COVID-32", "treatment": "treatment1" }
]
},
{
"firstName": "怡君",
"lastName": "王",
"age": 33,
"history": [
{"disease": "COVID-19", "treatment": "treatment1" },
{"disease": "COVID-32", "treatment": "treatment2" }
]
}
]
- 練習插入三筆記錄
db.patients.insertOne({
... "firstName": "Max",
... "lastName": "Schwarzmueller",
... "age": 29,
... "history": [
... {"disease": "cold", "treatment": "treatment2"},
... {"disease": "COVID-19", "treatment": "treatment1" }
... ]
... })
db.patients.insertMany([
... {
... "firstName": "小明",
... "lastName": "王",
... "age": 39,
... "history": [
... {"disease": "cold", "treatment": "treatment2"},
... {"disease": "COVID-19", "treatment": "treatment1" },
... {"disease": "COVID-32", "treatment": "treatment1" }
... ]
... },
... {
... "firstName": "怡君",
... "lastName": "王",
... "age": 33,
... "history": [
... {"disease": "COVID-19", "treatment": "treatment1" },
... {"disease": "COVID-32", "treatment": "treatment2" }
... ]
... }
... ])
- 練習更新一筆記錄
db.patients.replaceOne({ _id: ObjectId("646f6fda33e3ab77e3a6f3f8") }, { "firstName": "宜君", "lastName": "王", "age": 18, "history": [ { "disease": "COVID-19", "treatment": "treatment1" }, { "disease": "COVID-32", "treatment": "tre
patients> db.patients.replaceOne({_id: ObjectId("646f6fda33e3ab77e3a6f3f8")}, {
... "firstName": "宜君",
... "lastName": "王",
... "age": 18,
... "history": [
... {"disease": "COVID-19", "treatment": "treatment1" },
... {"disease": "COVID-32", "treatment": "treatment456" }
... ]
... })
db.patients.updateOne({firstName: "小明"}, {$set: {age: 31}})
- 練習用運算子查詢記錄
db.patients.find({age: {$gt: 28}})
- 練習刪除記錄提示
輸入 CRUD 指令時,若 filter 的目標鍵儲存值為 Array,仍可視為嵌入式結構,
用 " 夾住陣列內 document 的屬性。MongoDB 會將陣列內元素取出迭代處理。
db.patient.deleteMany({"history.disease": "cold"})