2017-02-06 85 views

回答

1

您可以使用聚合框架與$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這是lastUpdatedTimestampTTLinSeconds的總和域然後你就可以查詢爲:

db.collection.remove({ "expiryDate": { "$lt": new Date() }}); 

但儘管如此,這種低選擇性字段不會產生良好的指數表現,如果集合是非常大的。因此索引的候選集是大使用這種方法。

+0

非常感謝您的答覆和建議的解決方案。它看起來很優雅,但是我必須承認,我仍然在努力理解MongoDB中的聚合框架,尤其是它的語法。對於使用$ redact與簡單$哪裏有什麼建議? 此外,我不確定'TTLinSeconds'字段到'lastUpdatedTimestamp'的行是否會添加秒?{「$ add」:[「$ lastUpdatedTimestamp」,「$ TTLinSeconds」]}'? – Jacek

+0

非常感謝您的編輯!這是一個很好的學習經歷。還有一個問題:[文檔](https://docs.mongodb.com/manual/reference/operator/aggregation/add/)指出:'如果其中一個參數是日期,那麼$ add會將其他參數視爲毫秒添加到日期。「。我如何在'{「$ add」:[「$ lastUpdatedTimestamp」,「$ TTLinSeconds」]}'中將'$ TTLinSeconds'乘以1000? – Jacek

+0

要將秒轉換爲毫秒,您需要使用[**'$ multiply' **](https://docs.mongodb.com/manual/reference/operator/aggregation/multiply/#exp._S_multiply)運算符,作爲在最近的編輯中。 – chridam

5

這可能會實現(以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/

2

你可以做到這一點使用$where爲:

db.collectionName.remove({$where:"new Date().getTime() > this.lastUpdatedTimestamp.getTime() + (this.TTLinSeconds * 1000)"}) 
+0

謝謝!這很棒,我喜歡這個解決方案的簡單性。我不知道'this'關鍵字可以在MongoDB中使用。但有一個問題:這個解決方案與chridam提供的解決方案有什麼不同?也許有一個或另一個可能的性能問題? – Jacek

+0

那麼這兩種情況顯然都有一些「考慮因素」。對於'$ 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