本篇將要來說明MongoDB
中更新文檔的方法,並且也同時會說明更新修改器的功能,它能幫助我們進行更有效率的更新。
Update
。$set
、$inc
)。Update
~Update
函數主要的功用就如同字面所說,更新~,而使用方法如下,query
就是指你要先尋找更新的目標條件,update
就是你要更新的值。而另外三個參考請考下列。
true
,代表如果沒有找到該更新的對像,則新增,反之則否,默認是false
。false
,則代表你query
出多筆,他就只會更新第一筆,反之則都更新,默認是false
( !注意multi
只能在有修改器
時才能用 )。db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
下面來簡單示範一下用法。首先我們先新增三筆資料。
db.user.insert({"name":"mark","age":23});
db.user.insert({"name":"steven","age":23});
db.user.insert({"name":"jj","age":23});
然後我們將名字為mark
這人的age
改為18
,指令如下,query
為{"name":"mark"}
,query
的詳細用法會在find
那邊詳詳細細的說明。
db.user.update({"name":"mark"},{"name":"mark","age":18})
執行結果如下,不過誒……我只要更新age
也,為啥要全部換掉?
$set
、$inc
) ~$set
$set
修改器主要的功用就是用來指定一個字段的值,不用像上面一樣整個替換掉。
所以如我們如果要將mark
這位仁兄的age
改為18
只要下達下面的指令。
db.user.insert({"name":"mark","age":23});
db.user.insert({"name":"steven","age":23});
db.user.insert({"name":"jj","age":23});
db.user.update({"name":"mark"},{"$set" : { "age" : 18} })
執行結果如下,成功更新為age為18
$inc
假設一下情景,假如有個投票網站、或是要存放訪客數的功能,每次更新時都是要+1
,這種時後就可以用$inc
來更新你的document
,理論上來說速度應該會優於$set
,等會兒會來測試一下。
注意$inc
只能用在數值類型,否則就會提示Modifier $inc allowed for numbers only
。
我們寫段程式碼來看看他的使用方法,下面範例我們先新增一筆資料,然後我們每次更新時,like
都會加1
,所以我們更新3
次,理論上like
會變為3
。
db.home.insert({"id" : 1 ,"like" : 0})
db.home.update({"id" : 1},{"$inc" : {"like" : 1}})
db.home.update({"id" : 1},{"$inc" : {"like" : 1}})
db.home.update({"id" : 1},{"$inc" : {"like" : 1}})
執行結果如下,可以看到like
增加到3
了。
$set
與$inc
效能測試 ~假設一個情況,有個功能是存放訪客like
數,一樣每次更新時都是要+1
,我們這時來比較看看,來看看那個更新較快,測試的環境一樣使用nodejs
。
本測試會新增一筆資料然後更新n
次。如果n
為10
則更新結果要如下。
以下為程式碼,程式碼會放在此MyGithub。
程式碼簡單的說一下,首先會先用bulk insert
來建立一筆資料,然後接下來在產生n
個更新的promise
,最後用promise all
等所以promise
都更新完後,再結束計時。
debugger;
var mongodb = require('mongodb');
var mongodbServer = new mongodb.Server('localhost', 27017, {
auto_reconnect: true,
poolSize: 10
});
var db = new mongodb.Db('test', mongodbServer);
var count = 10;
db.open(function() {
db.collection('home', function(err, collection) {
/*
* Update use $set 測試
*/
var bulk = collection.initializeUnorderedBulkOp();
bulk.insert({
"id": 1,
"name": "mark",
"Like": 0
});
bulk.execute(function(err, res) {
console.time("update use $set");
var funcs = [];
for (var i = 1; i < count+1; i++) {
funcs.push(updateUseSet(i));
}
Promise.all(funcs).then((res) => {
console.timeEnd("update use $set");
});
});
function updateUseSet(i) {
return new Promise((resolve,reject) => {
collection.update({
"name": "mark"
}, {
"$set": {
"Like": i
}
}, function(err, res) {
resolve(i);
});
});
}
/*
* Update use $inc 測試
*/
var bulk = collection.initializeUnorderedBulkOp();
bulk.insert({
"id": 2,
"name": "steven",
"Like": 0
});
bulk.execute(function(err, res) {
var funcs = [];
udpateUseInc().then((res) => {
console.time("update use $inc");
for (var j = 1; j < count+1;j++) {
funcs.push(updateUseInc(1));
}
Promise.all(funcs).then((res) => {
console.timeEnd("update use $inc");
});
})
});
function updateUseInc() {
return new Promise((resolve,reject) => {
collection.update({
"name": "steven"
}, {
"$inc": {
"Like": 1
}
}, function(err, res) {
resolve();
});
});
}
});
});
測試結果,$inc
在更新數據時,完全贏過$set
。
測試案例(更新次數) | $set | $inc |
---|---|---|
10 | 39ms | 19ms |
1000 | 317ms | 257ms |
10000 | 4159ms | 3206ms |
50000 | 31893ms | 15929ms |
100000 | 154861ms | 129684ms |
事實上寫這篇時,一開始發現為啥$inc
執行時間總是大於$set
,不符合預期,一直覺得怪怪的後來查來了一下發現update
這方法執行時會lock
住DB
,所以上面的程式碼,第二個updateUseInc
要先執行一次確定updateUseSet
完畢後才開始計時。
P.S +u^5
之我感冒囉…