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.
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
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
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