本系列文章也刊登在我的部落格中,如有更新將以部落格為主~
前言
在上一篇文章中,我們介紹了 MongoDB 的基礎概念。
本篇文章是系列文的第二篇,要帶大家實際對 MongoDB 進行資料操作~
這篇文章將介紹資料的基本操作,包含:
Create
:創建資料Read
:讀取資料Update
:更新資料Delete
:刪除資料
Create 創建資料
在 MongoDB 創建資料的指令很單純,常用的有以下兩個:
insertOne
用於創建一筆新的 document。
下面的例子會在名為products
的 collection 中創建一筆紀錄了商品項目(item)
及商品數量(qty)
的 document:
db.products.insertOne( { item: "card", qty: 15 } );
insertMany
用於創建多筆新的 documents。
下面的例子會在名為products
的 collection 中創建三筆 documents。我們將要創建的多筆 documents 放在 Array 中,mongoDB 會依照 array 中 item 的順序去依序 insert:
db.products.insertMany( [
{ item: "card", qty: 15 },
{ item: "envelope", qty: 20 },
{ item: "stamps" , qty: 30, price: 1000 } // 有 price 資訊的 document
] );
還記得 MongoDB 的特性是 Schemaless
的嗎?在創建 document 時,每筆 document 都可以有不同的格式,如上面的stamps
有記錄價錢(price)
這個資訊,前面兩筆則沒有。
ObjectId
如果你透過 MongoDB shell 輸入上方的指令成功創建資料,會看見 MongoDB 回覆了一個 ObjectId
資訊。這個 ObjectId 是什麼呢?
其實我們每創建一筆資料時,MongoDB 都會主動賦予 document 一個獨特的_id
欄位,其值的type(資料格式)
就是我們看到的ObjectId
。我們通常會拿_id
當作該筆資料的主鍵
,因為 MongoDB 可以保證同一個 collection 中每筆 document 的_id
都是獨一無二的。
我們也可以使用自己定義的_id
作為 documet 主鍵。只需要在創建 document 時帶上_id
欄位就行,但我們需要保證自己定義的_id
不會重複,否則創建操作會失敗。
由於標準
JSON
中並沒有定義ObjectId
這個 type,由此可見 document 是以BSON
儲存,而不是常見的JSON
。
Read 讀取資料
MongoDB 中可以透過find
系列指令查詢資料。
find 與 findOne
單純使用find
而不帶參數時,會找到該 collection 中所有資料。
如下面的例子,我們會拿到記錄在 products 這個 collection 裡的所有 product:
db.products.find() // 拿回所有資料
一次拿回所有資料雖然方便但效率低落,因此在現實應用中很少這樣做。
我們通常會在find
指令中帶上query(查詢條件)
,用來找出符合我們需求的資料。
下面例子會找出_id = 5
的 document,由於我們知道_id
是獨一無二的,因此可以預期 MongoDB 只會返回一筆(或零筆)資料:
db.products.find( { _id: 5 } )
使用
find
會找出所有符合條件的 document。
使用findOne
時,會找出第一筆符合條件的 document。
Operators
MongoDB 提供了許多Operators(操作符)
讓搭配 query 使用,讓我們可以更精準描述想要查詢的資料。
如下面例子中我們使用$gt(greater than)
操作符,幫助我們查詢出所有 distance(距離)> 1000 的航班資訊:
db.flightData.find( { distance: { $gt: 1000 } })
另一個例子中我們使用$in
操作符,找出所有 bloodType(血型)是 A 或 B 的 user
db.users.find( { bloodType: { $in: ['A', 'B'] } } )
更詳細的 Operator 列表可以參考官方文件。
Cursor Object
當我們透過 shell 操作find
指令時,就算已經加上 query 條件,還是有機會一次拿回過多資料導致效率低落(想像你要搜尋姓氏開頭是 A 的使用者,可能超級超級多)。因為效率考量,使用 shell 的 find 指令時,MongoDB 其實是回傳一個Cursor Object
,而不是所有符合條件的資料。
Cursor Object 包含了:
- 部分資料:MongoDB 預設會回傳 20 筆資料
- 資料指針:指向目前拿到的最後一筆資料。我們可以透過
next
方法向 MongoDB 拿更多資料。
// 透過 find 指令找出所有血型是 A、B 的 user。拿到 mongoDB 回傳的 Cursor object
var myCursor = db.users.find( { bloodType: { $in: ['A', 'B'] } } );
// 把 cursor 中的資料轉換成 array,預設會拿 20 筆
var documentArray = myCursor.toArray();
// 透過 hasNext 檢查看看還有還有更多資料,有的話就透過 cursor 的 next 方法拿,並 print 出來
while (myCursor.hasNext()) {
printjson(myCursor.next());
}
關於 Cursor 的更多使用方法可以參考官方文件
Update 更新資料
更新跟創建的方式很像。可以選擇只更新一筆資料、也可以一次更新多筆資料。
updateOne
在操作更新時,我們使用 query 告訴 MongoDB「想要更新哪些資料」以及「如何更新他們」。
如下面的例子,我們在名為inventory
的 collection 中找尋item = paper
的資料,並且把資料的 size 更新為 100:
db.inventory.updateOne(
{ item: "paper" },
{
$set: { "size": 100 },
}
)
由於我們使用
updateOne
指令,就算符合 query 條件的資料有很多筆,MongoDB 也只會更新符合條件的第一筆 document。
updateMany
同上述的例子,如果指令換成updateMany
,則所有符合條件的資料都會被更新。
db.inventory.updateMany(
{ item: "paper" }, // 所有 item 欄位值是 paper 的資料都會被更新
{
$set: { "size": 100 },
}
)
使用updateMany
要注意的地方是,如果我們在 query 中沒有放上條件,則 collection 中的所有資料都會被更新,因此要小心使用!
db.inventory.updateMany(
{}, // 由於 query 為空,所有 document 都會加上 message 這個欄位
{
$set: { message: 'Oops' }
}
)
Delete 刪除資料
deleteOne 與 deleteMany
刪除資料的邏輯跟查詢一樣,我們必須在 query 中描述要被刪除的資料條件。
下述例子會將_id = 5
的 document 刪除:
db.products.deleteOne( { _id: 5 } )
相同的,我們可以透過deleteMany
一次刪除多筆資料。
下面例子會將血型為 A 的 user 全部刪除:
db.user.deleteMany(
{ bloodType: "A" }, // 所有血型為 A 的 user 都被刪除
)
要注意的是,如果我們在 query 中沒有放上條件,就會把 collection 裡的所有 documents 全部刪除,因此要謹慎使用!
db.inventory.deleteMany({}) // 清空 inventory Collection
總結
本篇文章介紹了 MongoDB 中基本的CRUD
指令。
基本上透過這些指令已經能應付大多數的操作。關於每個指令的詳細介紹可以參考官方文件。
下篇文章我們將針對更強大的Aggregate
操作做介紹。
BitWise 分享
除了參與本次 寫作松
分享軟體開發的技術之外,
我在 Podcast 節目 【 BitWise 一點智慧 】
中也會以輕鬆的角度,跟大家聊聊軟體開發、設計、學習!歡迎大家收聽~~
👉 用Apple收聽
👉 用Spotify收聽
👉 用Google收聽
👉 官方網站