[英]MongoDB update/insert document and Increment the matched array element
我將Node.js和MongoDB與monk.js結合使用,我希望以最小的方式每小時記錄一個文檔,例如:
最終文件:
{時間:YYYY-MM-DD-HH,日志:[{動作:action1,計數:1},{動作:action2,計數:27},{動作:action3,計數:5}]}
完整的文檔應通過增加一個值來創建。
例如,這個小時有人首先訪問網頁,而action1的增加應創建帶有查詢的以下文檔:
{時間:YYYY-MM-DD-HH,日志:[{action:action1,count:1}]}
在這個小時內,另一個用戶訪問了另一個網頁,文檔應被排除在:
{時間:YYYY-MM-DD-HH,日志:[{動作:action1,計數:1},{動作:action2,計數:1}]}
並且訪問不同網頁時,計數值應該增加。
目前,我為每個動作創建一個文檔:
tracking.update({time:moment()。format('YYYY-MM-DD_HH'),action:action,info:info},{$ inc:{count:1}},{upsert:true},函數(呃){}
monk.js / mongodb是否可能?
編輯:謝謝。 您的解決方案看上去干凈優雅,但看起來我的服務器無法處理它,或者我要nooby使其正常工作。
我寫了一個極端的骯臟的解決方案,以動作名稱作為鍵:
tracking.update({time:time,ts:ts},JSON.parse('{“ $ inc”:{“'+ action +'”:1}}'),{upsert:true},function(err){ });
是的,這是很有可能的,也是一個深思熟慮的問題。 我對該方法所做的唯一修改是將“時間”值計算為一個實際的Date
對象(在MongoDB中非常有用,並且也可以進行操縱),但只需使用基本日期數學將值“四舍五入”即可。 您可以使用“ moment.js”獲得相同的結果,但是我發現數學很簡單。
此處的另一個主要考慮因素是將數組“推送”操作與可能的“ updsert”文檔操作混合在一起可能是一個實際問題,因此最好使用“多個”更新語句來處理此問題,在這種情況下,只需要更改條件任何東西。
最好的方法是使用MongoDB Bulk Operations 。
考慮一下您的數據是這樣的:
{ "timestamp": 1439381722531, "action": "action1" }
其中“時間戳”是紀元時間戳值,精確到毫秒。 因此,此處理看起來像:
// Just adding for the listing, assuming already defined otherwise
var payload = { "timestamp": 1439381722531, "action": "action1" };
// Round to hour
var hour = new Date(
payload.timestamp - ( payload.timestamp % ( 1000 * 60 * 60 ) )
);
// Init transaction
var bulk = db.collection.initializeOrderedBulkOp();
// Try to increment where array element exists in document
bulk.find({
"time": hour,
"log.action": payload.action
}).updateOne({
"$inc": { "log.$.count": 1 }
});
// Try to upsert where document does not exist
bulk.find({ "time": hour }).upsert().updateOne({
"$setOnInsert": {
"log": [{ "action": payload.action, "count": 1 }]
}
});
// Try to "push" where array element does not exist in matched document
bulk.find({
"time": hour,
"log.action": { "$ne": payload.action }
}).updateOne({
"$push": { "log": { "action": payload.action, "count": 1 } }
});
bulk.execute();
因此,如果您仔細研究那里的邏輯,那么您將發現,對於任何給定的文檔狀態,無論存在與否,這些語句中的“一個”都只有可能是正確的。 從技術上來講,帶有“ upsert”的語句實際上可以與文檔匹配,但是,使用的$setOnInsert
操作可以確保不進行任何更改,除非該操作實際上“插入”了新文檔。
由於所有操作均以“批量”方式觸發,因此僅在.execute()
調用中與服務器聯系。 因此,盡管有多個操作,但是對服務器只有“一個”請求,只有“一個”響應。 它實際上是一個請求。
這樣就可以滿足所有條件:
為當前不存在的期間創建一個新文檔,並將初始數據插入到數組中。
將新項目添加到當前“操作”分類不存在的數組中,並添加初始計數。
執行語句后,增加數組中指定操作的count屬性。
總而言之,是有可能的,而且對於存儲來說也是個好主意,只要操作分類在一段時間內不會增長得太大(應將500個數組元素用作最大指導)並且更新非常有效且包含在其中每個時間樣本一個文檔。
該結構也很好,非常適合其他查詢以及可能的其他聚合目的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.