MongoDB的集合中的文件有以下模式刪除文件(只顯示相關字段):按日期的總和和數字領域和當前時間戳之間的日期比較
{
"TTLinSeconds" : 1800,
"lastUpdatedTimestamp" : ISODate("...")
}
我需要刪除所有文件,其中current timestamp
大於lastUpdatedTimestamp
加上存儲在TTLinSeconds
字段中的值。預先感謝您的建議。
MongoDB的集合中的文件有以下模式刪除文件(只顯示相關字段):按日期的總和和數字領域和當前時間戳之間的日期比較
{
"TTLinSeconds" : 1800,
"lastUpdatedTimestamp" : ISODate("...")
}
我需要刪除所有文件,其中current timestamp
大於lastUpdatedTimestamp
加上存儲在TTLinSeconds
字段中的值。預先感謝您的建議。
您可以使用聚合框架與$redact
和$out
管道刪除文件滿足給定的條件。
的$redact
管道結合的$project
和$match
的功能來實現現場級新版本,其中將返回使用$$KEEP
符合條件的所有文件,並刪除那些不使用$$PRUNE
變量相匹配。
$out
流水線將聚合流水線的結果文檔寫入同一個集合,從而基本上執行更新操作。
運行下面的總操作將刪除文件:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$lte": [
new Date(),
{
"$add": [
"$lastUpdatedTimestamp",
{ "$multiply": ["$TTLinSeconds", 1000] }
]
}
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{ "$out": "collection" }
])
至於警告,使用$where
運營商,因爲它需要一段時間來處理將不執行得很好因爲MongoDB在幕後做了什麼:當你執行一個普通的查詢時,你的客戶端把這個查詢轉換成BSON d將它發送到數據庫。 MongoDB也將數據存儲在BSON中,因此它可以基本上將您的查詢與數據進行比較。這是非常快速和高效的。
在另一方面,當你有一個必須作爲查詢的一部分來執行的$where
條款,MongoDB的將要創建的集合中的每個文檔中的JavaScript對象,解析文件BSON,再添加全部的字段添加到JavaScript對象中。然後執行您發送的JavaScript文檔,然後再將其全部撕下。這是一個非常耗費時間和資源的操作,因爲它調用JavaScript引擎來評估每個文檔上的Javascript代碼並檢查每個文檔的條件。如果可以的話,建議與索引查詢結合使用,以便查詢速度更快。
一些considerations你要看看使用$where
當:
不要使用全局變量。
$where
評估JavaScript並且不能利用索引。 因此,當您使用標準MongoDB的運營商表達你的查詢 查詢性能提高(例如,$gt
,$in
)。一般而言,只有當您無法使用其他 運算符表示您的查詢時,您應使用$where
。如果您必須使用$where
,請嘗試包含至少一個其他 標準查詢運算符以過濾結果集。使用$where
單獨 需要表掃描。在使用普通非$where
查詢語句 提供以下性能優勢:的MongoDB將前
$where
報表評估查詢的非$where
組件。如果非$where
語句不匹配任何文檔,MongoDB 將不會執行任何查詢評估使用$where
。非查詢語句可以使用索引。
$where
是一個不錯的黑客在必要的時候,但應儘可能避免。如果需要$where
查詢,您可以減少對性能通過減少文件的數量命中,這讓到$where
或創建一個額外的計算非規範化的領域說expiryDate
這是lastUpdatedTimestamp
和TTLinSeconds
的總和域然後你就可以查詢爲:
db.collection.remove({ "expiryDate": { "$lt": new Date() }});
但儘管如此,這種低選擇性字段不會產生良好的指數表現,如果集合是非常大的。因此索引的候選集是大使用這種方法。
這可能會實現(以2017-01-25T00之間刪除場:30:00Z和2017-01-26T23:59:00Z):
db.collectionName.remove({
$and : [
{"lastUpdatedTimestamp": {
$gte: ISODate("2017-01-25T00:30:00Z"),
$lt : ISODate("2017-01-26T23:59:00Z")
},
{"TTLinSeconds" : value}
]
}
建議:
我建議你爲變量使用通用命名約定。
參考:
https://docs.mongodb.com/manual/reference/operator/update/currentDate/
你可以做到這一點使用$where爲:
db.collectionName.remove({$where:"new Date().getTime() > this.lastUpdatedTimestamp.getTime() + (this.TTLinSeconds * 1000)"})
謝謝!這很棒,我喜歡這個解決方案的簡單性。我不知道'this'關鍵字可以在MongoDB中使用。但有一個問題:這個解決方案與chridam提供的解決方案有什麼不同?也許有一個或另一個可能的性能問題? – Jacek
那麼這兩種情況顯然都有一些「考慮因素」。對於'$ where',你可以看到https://docs.mongodb.com/manual/reference/operator/query/where/#considerations。同樣,對於'aggregation',你可以看到http://stackoverflow.com/questions/38840669/mongodb-aggregation-performance-capability。而'$ redact',你可以看到:http://stackoverflow.com/questions/32653442/redact-in-mongodb-seems-obscure-to-me。我還建議您對兩個查詢執行'explain()'以查看兩個查詢在您的設置上的表現如何。 – oblivion
非常感謝您的答覆和建議的解決方案。它看起來很優雅,但是我必須承認,我仍然在努力理解MongoDB中的聚合框架,尤其是它的語法。對於使用$ redact與簡單$哪裏有什麼建議? 此外,我不確定'TTLinSeconds'字段到'lastUpdatedTimestamp'的行是否會添加秒?{「$ add」:[「$ lastUpdatedTimestamp」,「$ TTLinSeconds」]}'? – Jacek
非常感謝您的編輯!這是一個很好的學習經歷。還有一個問題:[文檔](https://docs.mongodb.com/manual/reference/operator/aggregation/add/)指出:'如果其中一個參數是日期,那麼$ add會將其他參數視爲毫秒添加到日期。「。我如何在'{「$ add」:[「$ lastUpdatedTimestamp」,「$ TTLinSeconds」]}'中將'$ TTLinSeconds'乘以1000? – Jacek
要將秒轉換爲毫秒,您需要使用[**'$ multiply' **](https://docs.mongodb.com/manual/reference/operator/aggregation/multiply/#exp._S_multiply)運算符,作爲在最近的編輯中。 – chridam