2017-02-06 1 views

Antwort

1

können Sie die Aggregation verwenden Rahmen mit den $redact und $out Pipelines, die Dokumente zu entfernen welche die gegebene Bedingung erfüllen.

Die $redact Pipeline enthält die Funktionalität von $project und $match Feldebene Schwärzung zu implementieren, wo sie alle Dokumente, die Bedingung $$KEEP mit passenden und entfernt diejenigen, die nicht die $$PRUNE Variable passen .

Die $out Pipeline schreibt die resultierenden Dokumente der Aggregationspipeline in die gleiche Auflistung und führt somit im Wesentlichen eine Aktualisierungsoperation aus.


die folgende Gesamtbetrieb ausführen, werden die Dokumente entfernen:

db.collection.aggregate([ 
    { 
     "$redact": { 
      "$cond": [ 
       { 
        "$lte": [ 
         new Date(), 
         { 
          "$add": [ 
           "$lastUpdatedTimestamp", 
           { "$multiply": ["$TTLinSeconds", 1000] } 
          ] 
         } 
        ] 
       }, 
       "$$KEEP", 
       "$$PRUNE" 
      ] 
     } 
    }, 
    { "$out": "collection" } 
]) 

Als Einschränkung, die $where Operator wird nicht sehr gut durchführen, wie es eine Weile dauert, die verarbeiten Abfrage, was MongoDB hinter den Kulissen macht: Wenn Sie eine normale (nicht $where) Abfrage ausführen, wandelt Ihr Client diese Abfrage in BSON ein d sendet es an die Datenbank. MongoDB speichert Daten auch in BSON, so dass Ihre Abfrage im Grunde direkt mit den Daten verglichen werden kann. Dies ist sehr schnell und effizient.

Auf der anderen Seite, wenn Sie eine $where Klausel haben, die als Teil der Abfrage ausgeführt werden müssen, MongoDB wird ein JavaScript-Objekt für jedes Dokument in der Sammlung erstellen müssen, die Dokumente BSON Parsen und alle Hinzufügen ihrer Felder auf die JavaScript-Objekte. Es führt dann das JavaScript aus, das Sie für die Dokumente gesendet haben, und reißt es dann erneut ab. Dies ist ein extrem zeit- und ressourcenintensiver Vorgang, da die JavaScript-Engine aufgerufen wird, um den JavaScript-Code für jedes Dokument zu bewerten und die Bedingung für jedes Dokument zu prüfen. Es empfiehlt sich, mit indizierten Abfragen zu kombinieren, um die Abfrage schneller zu machen.

Einige considerations Sie haben zu sehen, wenn $where mit:

keine globalen Variablen anwenden.

$where wertet JavaScript aus und kann Indizes nicht nutzen. Daher Abfrageleistung verbessert, wenn Sie Ihre Abfrage mit den Standard MongoDB Operatoren ausdrücken (zum Beispiel $gt, $in). Im Allgemeinen sollten Sie $where nur verwenden, wenn Sie Ihre Abfrage nicht mit einem anderen Operator ausdrücken können. Wenn Sie $where verwenden müssen, versuchen Sie, mindestens einen anderen Standardabfrageoperator einzubeziehen, um die Ergebnismenge zu filtern. Mit $where allein erfordert einen Tabellenscan. Mit normalen nicht $where Abfrageanweisungen folgende Leistungsvorteile bietet:

MongoDB wertet nicht $where Komponenten der Abfrage vor $where Aussagen. Wenn die Anweisungen nicht mit Dokumenten übereinstimmen, führt MongoDB keine Abfrageauswertung mit $where aus. Die Abfrageanweisungen können einen Index verwenden.

$where ist ein guter Hack, wenn notwendig, aber es sollte möglichst vermieden werden. Wenn eine $where Abfrage benötigt wird, können Sie auf der Leistung abgeholzt getroffen, indem die Anzahl von Dokumenten zu minimieren, die es die $where oder erstellen Sie ein zusätzliches berechnetes normalisiert Feld machen sagen expiryDate, dass die Summe der lastUpdatedTimestamp und die TTLinSeconds Felder, die Sie dann als abfragen:

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

Aber noch so niedriges Selektivität Felder ergeben keine gute Index-Performance, wenn die Sammlung sehr groß sind also der Kandidatensatz für die Indizierung ist groß, mit diesem Ansatz.

+0

Vielen Dank für Ihre Antwort und vorgeschlagene Lösung. Es sieht elegant aus, aber ich muss zugeben, dass ich immer noch damit zu kämpfen habe, das Aggregations-Framework in MongoDB zu verstehen, insbesondere seine Syntax. Würde es irgendwelche Empfehlungen geben, $ redact gegen simple $ zu verwenden? Auch bin ich nicht sicher, dass die Zeile '{" $ add ": [" $ lastUpdatedTimestamp "," $ TTLinSeconds "]}' Sekunden aus dem 'TTLinSeconds' Feld zum' lastUpdatedTimestamp' hinzufügen? – Jacek

+0

Vielen Dank für Ihre Änderungen! Es war eine gute Lernerfahrung. Eine weitere Frage: [Die Dokumentation] (https://docs.mongodb.com/manual/reference/operator/aggregation/add/) state: 'Wenn eines der Argumente ein Datum ist, behandelt $ add die anderen Argumente als Millisekunden dem Datum hinzufügen. Wie kann ich $ TTLinSeconds um 1000 in '{" $ add ": [" $ lastUpdatedTimestamp "," $ TTLinSeconds "]}' '? – Jacek

+0

Um Sekunden in Millisekunden zu konvertieren, müssen Sie den Operator [** '$ multiply' **] (https://docs.mongodb.com/manual/reference/operator/aggregation/multiply/#exp._S_multiply) verwenden in der letzten Bearbeitung. – chridam

5

Dies könnte funktionieren (Feld löschen zwischen 2017-01-25T00: 30: 00Z 2017-01-26T23 und: 59: 00Z):

db.collectionName.remove({ 
     $and : [ 
     {"lastUpdatedTimestamp": { 
      $gte: ISODate("2017-01-25T00:30:00Z"), 
      $lt : ISODate("2017-01-26T23:59:00Z") 
     }, 
     {"TTLinSeconds" : value} 
     ] 
    } 

Vorschlag:

Ich würde Ihnen empfehlen Verwenden Sie die allgemeine Namenskonvention für Ihre Variablen.

Referenz:

https://docs.mongodb.com/manual/reference/operator/update/currentDate/

2

Sie könnten dies tun mit $where wie:

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

Danke! Das ist großartig, ich mag die Einfachheit dieser Lösung. Ich wusste nicht, dass 'this' Schlüsselwort in MongoDB verwendet werden kann. Eine Frage: Wie unterscheidet sich diese Lösung von der von chridam? Vielleicht gibt es mögliche Leistungsprobleme mit dem einen oder anderen? – Jacek

+0

Nun, es gibt offensichtlich einige "Überlegungen" für beide Fälle. Für '$ where' könnten Sie https://docs.mongodb.com/manual/reference/operator/query/where/#considerations sehen. Ähnlich könnten Sie für "Aggregation" http://stackoverflow.com/questions/38840669/mongodb-aggregation-performance-capability sehen. Und für $ redact können Sie sehen: http: //stackoverflow.com/questions/32653442/redact-in-mongodb-seems-obscure-to-me. Außerdem empfehle ich Ihnen, 'explain()' in beiden Abfragen auszuführen, um zu sehen, wie gut beide Abfragen in Ihrem Setup funktionieren. – oblivion

Verwandte Themen