MongoDB 更多更新操作
批次新增
- 一次送出多筆資料會比逐筆新增來得快
- 可以用命令列工具 mongoimport 來匯入資料,不用一直呼叫 insertMany
- Message size can’t be larger than 48 MB
> db.movies.insertMany([{"title":"Movie 1"},{"title":"Movie 2"},{"title":"Movie 3"}])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5f6876732fbc27989eb7f4c2"),
ObjectId("5f6876732fbc27989eb7f4c3"),
ObjectId("5f6876732fbc27989eb7f4c4")
]
}
有序與無序新增
有序新增(預設):只要有一筆資料新增失敗,MongoDB 就會停止後續的新增
無序新增:不管有沒有失敗,MongoDB 都會嘗試新增所有資料,無序新增的效能會比較好
刪除集合
ex. db.movies.drop()
> db.movies.insertOne(movie2)
{
"acknowledged" : true,
"insertedId" : ObjectId("5f68e75e85d32460c3bfa6e3")
}
> db.movies.find().pretty()
{
"_id" : ObjectId("5f68e75885d32460c3bfa6e2"),
"title" : "A movie",
"director" : "A director",
"year" : 2020
}
{
"_id" : ObjectId("5f68e75e85d32460c3bfa6e3"),
"title" : "A movie 2",
"director" : "A director 2",
"year" : 2020
}
> db.movies.drop()
true
> db.movies.find().pretty()
更新
更新看起來是原子操作,但我好奇如果兩個更新操作同時發生,而第二個操作的篩選條件因為第一個操作修改了資料而不再符合,會發生什麼事?
> db.movies.find().pretty()
{
"_id" : ObjectId("5f6950a694d2d7702605f470"),
"title" : "A movie",
"director" : "A director",
"year" : 2020
}
{
"_id" : ObjectId("5f6950a794d2d7702605f471"),
"title" : "A movie 2",
"director" : "A director 2",
"year" : 2020
}
// Update one movie
> db.movies.updateOne({"title":"A movie"},{$set:{"year":2021,"review":0}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.movies.find({"title":"A movie"}).pretty()
{
"_id" : ObjectId("5f6950a694d2d7702605f470"),
"title" : "A movie",
"director" : "A director",
"year" : 2021,
"review" : 0
}
替換
replace 指令會替換整個文件
> db.movies.replaceOne({"title":"A movie"}, {"title":"B movie", "year":1990})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.movies.find().pretty()
{
"_id" : ObjectId("5f6950a694d2d7702605f470"),
"title" : "B movie",
"year" : 1990
}
{
"_id" : ObjectId("5f6950a794d2d7702605f471"),
"title" : "A movie 2",
"director" : "A director 2",
"year" : 2020
}
遞增一個數值
// create page document
> pageA= {"page":"page A", "view":0}
{ "page" : "page A", "view" : 0 }
> db.page.insertOne(pageA)
{
"acknowledged" : true,
"insertedId" : ObjectId("5f69551d94d2d7702605f472")
}
// check data
> db.page.find({"page":"page A"}).pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"view" : 0
}
// increment
> db.page.updateOne({"page":"page A"},{"$inc":{"view":1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
// check result
> db.page.find({"page":"page A"}).pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"view" : 1
}
$unset
// check there is a view property
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"view" : 1
}
// unset view property
> db.page.updateOne({"page":"page A"},{"$unset":{"view":1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
// check view property disappeared
> db.page.find().pretty()
{ "_id" : ObjectId("5f69551d94d2d7702605f472"), "page" : "page A" }
$set 修改內嵌文件的屬性值
// set new property: user
> db.page.updateOne({"page":"page A"}, {"$set":{
... "user":{
... "display_name":"",
... "devices":[
...
... ],
... "subscriptions":{
... "vpn":{
... "active":true,
... }
... },
... "max_devices":5
... },
... }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
// check data
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"user" : {
"display_name" : "",
"devices" : [ ],
"subscriptions" : {
"vpn" : {
"active" : true
}
},
"max_devices" : 5
}
}
// change display_name
> db.page.updateOne({"page":"page A"},{"$set":{"user.display_name":"ABCDE"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
// check update result
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"user" : {
"display_name" : "ABCDE",
"devices" : [ ],
"subscriptions" : {
"vpn" : {
"active" : true
}
},
"max_devices" : 5
}
}
$push 新增資料到陣列屬性
// push data to array attribute
> db.page.updateOne({"page":"page A"},{"$push":{"comment":"hello"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.page.updateOne({"page":"page A"},{"$push":{"comment":"hello2"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
// check result
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"comment" : [
"hello",
"hello2"
]
}
用 $each 搭配 $push 新增多個元素到陣列屬性
// Can't add multiple elements to an array by simply $push
> db.page.updateOne({"page":"page A"},{"$push":{"comment":["hello3","hello4"]}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
// Because only $push will add only one element, thus one element with array value will be added
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"comment" : [
"hello",
"hello2",
[
"hello3",
"hello4"
]
]
}
// Need $each to add multiple elements
> db.page.updateOne({"page":"page A"},{"$push":{"comment":{"$each":["hello3","hello4"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"comment" : [
"hello",
"hello2",
[
"hello3",
"hello4"
],
"hello3",
"hello4"
]
}
執行 $each 時用 $slice 把陣列切成 3 個元素
> db.page.updateOne({"page":"page A"},{"$push":{"comment":{"$each":[],"$slice":-3}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
// rest 3 records
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"comment" : [
[
"hello3",
"hello4"
],
"hello3",
"hello4"
]
}
$slice 時同時 $sort
> db.page.updateOne({"page":"page A"},{"$push":{"top3":{"$each":[{"name":"A","height":5},{"name":"B","height":4},{"name":"C","height":3},{"name":"D","height":2},{"name":"E","height":1}],"$slice":-3,"$sort":{"height":1}}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.page.find().pretty()
{
"_id" : ObjectId("5f69551d94d2d7702605f472"),
"page" : "page A",
"comment" : [
"hello3",
"hello4"
],
"top3" : [
{
"name" : "C",
"height" : 3
},
{
"name" : "B",
"height" : 4
},
{
"name" : "A",
"height" : 5
}
]
}
$push 留言
> db.users.updateOne({"name":"user1"},{"$push":{"comment":{"email":"a@gmail.com"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.updateOne({"name":"user1"},{"$push":{"comment":{"email":"b@gmail.com"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6a38748074fb4051b75cb8"),
"name" : "user1",
"comment" : [
{
"email" : "a@gmail.com"
},
{
"email" : "b@gmail.com"
}
]
}
$push 之後再用 $addToSet 搭配 $each 加入電話
> user = {"name":"user 1"}
{ "name" : "user 1" }
> db.users.insertOne(user)
{
"acknowledged" : true,
"insertedId" : ObjectId("5f6c46393c90a681c72b7df5")
}
> db.users.updateOne({"name":"user 1"},{$push:{"phone":"123456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"123456"
]
}
// add existing phone, no modification
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": "123456"}})
{ "acknowledged" : true, “matchedCount" : 1, "modifiedCount" : 0 }
// add new phone
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": "223456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"123456",
"223456"
]
}
// add existing phone, no modification
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": "223456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
// add multiple elements by $each, one non-existing phone, so one modification
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": {"$each":["223456","12345"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": {"$each":["223456","12345","123456"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"123456",
"223456",
"12345"
]
}
用 $pop 移除元素,$pop 1 從尾端移除,$pop -1 從開頭移除
> db.users.updateOne({"name":"user 1"}, {"$pop":{"phone": 1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"123456",
"223456"
]
}
> db.users.updateOne({"name":"user 1"}, {"$pop":{"phone": -1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456"
]
}
用 $pull 移除元素
// pull element but value is not matched, no modification
> db.users.updateOne({"name":"user 1"}, {"$pull":{"phone":"123456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
//
> db.users.updateOne({"name":"user 1"}, {"$pull":{"phone":"223456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [ ]
}
用 $pull 移除多個元素
// push elements
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": {"$each":["223456","12345","123456"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"123456"
]
}
> db.users.updateOne({"name":"user 1"}, {$push:{"phone": {"$each":["223456","12345","123456"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"123456",
"223456",
"12345",
"123456"
]
}
// pull 123456, all 123456 will be removed
> db.users.updateOne({"name":"user 1"}, {"$pull":{"phone":"123456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
]
}
$inc 遞增指定陣列索引的值
// original data
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
]
}
// push 2 comments
> db.users.updateOne({"name":"user 1"}, {$push:{"comment":{"vote":0,"message":"haha"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.updateOne({"name":"user 1"}, {$push:{"comment":{"vote":0,"message":"haha 2"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 0,
"message" : "haha"
},
{
"vote" : 0,
"message" : "haha 2"
}
]
}
// increase the first element vote
> db.users.updateOne({"name":"user 1"}, {"$inc":{"comment.0.vote":1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 1,
"message" : "haha"
},
{
"vote" : 0,
"message" : "haha 2"
}
]
}
// increase 100 to the second element
> db.users.updateOne({"name":"user 1"}, {"$inc":{"comment.1.vote":100}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 1,
"message" : "haha"
},
{
"vote" : 100,
"message" : "haha 2"
}
]
}
// update message when array element match arrayFilters
> db.users.updateOne({"name":"user 1"}, {$set:{"comment.$[elmt].message":"Good"}},{arrayFilters:[{"elmt.vote":{$lte: 11}}]})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 1,
"message" : "Good"
},
{
"vote" : 100,
"message" : "haha 2"
}
]
}
upsert:存在就更新,不存在就新增
// upsert age to user 1
> db.users.updateOne({"name":"user 1"},{"$set":{"age":10}},{"upsert":true})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 1,
"message" : "Good"
},
{
"vote" : 100,
"message" : "haha 2"
}
],
"age" : 10
}
// upsert age to user 2
> db.users.updateOne({"name":"user 2"},{"$set":{"age":10}},{"upsert":true})
{
"acknowledged" : true,
"matchedCount" : 0,
"modifiedCount" : 0,
"upsertedId" : ObjectId("5f6d6fa0d8c8c1bae1785718")
}
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 1,
"message" : "Good"
},
{
"vote" : 100,
"message" : "haha 2"
}
],
"age" : 10
}
{
"_id" : ObjectId("5f6d6fa0d8c8c1bae1785718"),
"name" : "user 2",
"age" : 10
}
$setOnInsert 在新增時設定屬性
// set createdAt when insert
> db.users.updateOne({"name":"user 2"},{"$setOnInsert":{"createdAt":new Date()}},{"upsert":true})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 1,
"message" : "Good"
},
{
"vote" : 100,
"message" : "haha 2"
}
],
"age" : 10
}
{
"_id" : ObjectId("5f6d6fa0d8c8c1bae1785718"),
"name" : "user 2",
"age" : 10
}
//
> db.users.updateOne({"name":"user 3"},{"$setOnInsert":{"createdAt":new Date()}},{"upsert":true})
{
"acknowledged" : true,
"matchedCount" : 0,
"modifiedCount" : 0,
"upsertedId" : ObjectId("5f6d738ed8c8c1bae1785730")
}
> db.users.find().pretty()
{
"_id" : ObjectId("5f6c46393c90a681c72b7df5"),
"name" : "user 1",
"phone" : [
"223456",
"12345",
"223456",
"12345"
],
"comment" : [
{
"vote" : 1,
"message" : "Good"
},
{
"vote" : 100,
"message" : "haha 2"
}
],
"age" : 10
}
{
"_id" : ObjectId("5f6d6fa0d8c8c1bae1785718"),
"name" : "user 2",
"age" : 10
}
{
"_id" : ObjectId("5f6d738ed8c8c1bae1785730"),
"name" : "user 3",
"createdAt" : ISODate("2020-09-25T04:35:26.398Z")
}
findOneAndUpdate 可以處理 race condition,但預設回傳的是修改前的舊文件。
可以用 returnNewDocument 來回傳修改後的文件
// update and return old document
> db.users.findOneAndUpdate({"name":"user1"},{"$push":{"phone":{"$each":["123456"]}}})
{
"_id" : ObjectId("5f6a38748074fb4051b75cb8"),
"name" : "user1",
"comment" : [
{
"email" : "a@gmail.com"
},
{
"email" : "b@gmail.com"
}
]
}
// update and return new document
> db.users.findOneAndUpdate({"name":"user1"},{"$push":{"phone":{"$each":["1234567"]}}},{"returnNewDocument":true})
{
"_id" : ObjectId("5f6a38748074fb4051b75cb8"),
"name" : "user1",
"comment" : [
{
"email" : "a@gmail.com"
},
{
"email" : "b@gmail.com"
}
],
"phone" : [
"123456",
"1234567"
]
}