簡體   English   中英

MongoDB更新/插入文檔並增加匹配的數組元素

[英]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()調用中與服務器聯系。 因此,盡管有多個操作,但是對服務器只有“一個”請求,只有“一個”響應。 它實際上是一個請求。

這樣就可以滿足所有條件:

  1. 為當前不存在的期間創建一個新文檔,並將初始數據插入到數組中。

  2. 將新項目添加到當前“操作”分類不存在的數組中,並添加初始計數。

  3. 執行語句后,增加數組中指定操作的count屬性。

總而言之,是有可能的,而且對於存儲來說也是個好主意,只要操作分類在一段時間內不會增長得太大(應將500個數組元素用作最大指導)並且更新非常有效且包含在其中每個時間樣本一個文檔。

該結構也很好,非常適合其他查詢以及可能的其他聚合目的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM