Wenn Sie diese Art von Einschränkung in der Abfrage wünschen, haben Sie grundsätzlich zwei Möglichkeiten, je nachdem, was Ihre MongoDB-Version unterstützt:
MongoDB 3.6
Sie würden vorzugsweise $expr
verwenden
"zusätzlich" zu allen normalen Abfragebedingungen, um tatsächlich gültige Dokumente auszuwählen:
var A = 10, B = 40;
Model.find({
"subDocs.value": { "$all": [A, B] },
"$expr": {
"$lt": [
{ "$arrayElemAt": [
"$subDocs.index",
{ "$indexOfArray": [ "$subDocs.value", A ]}
]},
{ "$arrayElemAt": [
"$subDocs.index",
{ "$indexOfArray": [ "$subDocs.value", B ]}
]}
]
}
})
Oder passend zum "letzten" Auftreten:
Model.find({
"subDocs.value": { "$all": [A, B] },
"$expr": {
"$lt": [
{ "$arrayElemAt": [
"$subDocs.index",
{ "$subtract": [
{ "$subtract": [{ "$size": "$subDocs.value" }, 1 ] },
{ "$indexOfArray": [ { "$reverseArray": "$subDocs.value" }, A ] }
]}
]},
{ "$arrayElemAt": [
"$subDocs.index",
{ "$subtract": [
{ "$subtract": [{ "$size": "$subDocs.value" }, 1 ] },
{ "$indexOfArray": [ { "$reverseArray": "$subDocs.value" }, B ] }
]}
]}
]
}
})
Frühere Versionen
Dasselbe, aber ohne native Operatoren müssen Sie die JavaScript-Evaluierung von
var A = 10, B = 40;
Model.find({
"subDocs.value": { "$all": [A, B] },
"$where": `this.subDocs.find( e => e.value === ${A}).index
< this.subDocs.find( e => e.value === ${B}).index`
})
Oder passend zum "letzten" Auftreten:
Model.find({
"subDocs.value": { "$all": [10,40] },
"$where": `let arr = this.subDocs.reverse();
return arr.find( e => e.value === ${A}).index
> arr.find( e => e.value === ${B}).index`
})
Wenn Sie dies in einer Aggregationspipeline benötigen, verwenden Sie $schwärzen
und stattdessen eine ähnliche Logik wie im ersten Beispiel:
var A = 10, B = 40;
Model.aggregate([
{ "$match": { "subDocs.value": { "$all": [A, B] } } },
{ "$redact": {
"$cond": {
"if": {
"$lt": [
{ "$arrayElemAt": [
"$subDocs.index",
{ "$indexOfArray": [ "$subDocs.value", A ]}
]},
{ "$arrayElemAt": [
"$subDocs.index",
{ "$indexOfArray": [ "$subDocs.value", B ]}
]}
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Es genügt zu sagen, dass die "Vergleichslogik" eigentlich nicht in "Abfrageoperatorausdrücken" selbst enthalten ist, also der einzige Teil, der "optimal" ist kann auf einen Index angewendet werden, indem der $all
Abfrageoperator in allen Fällen. Die wesentliche verbleibende Logik gilt tatsächlich "nach" der Auswertung dieses Hauptausdrucks und "zusätzlich zu", damit keine anderen Ergebnisse zurückgegeben werden als diejenigen, die den Ausdruck entweder mit $expr
oder $where
.
Die grundlegende Logik von jedem besteht im Wesentlichen darin, den Wert des "index"
zu extrahieren -Eigenschaft aus dem "ersten" Arraymitglied, das tatsächlich mit dem jeweiligen Wert in "value"
übereinstimmt Eigentum. Wo dies "kleiner als" ist, dann ist die Bedingung true
und dies erfüllt das zurückgegebene Dokument.
Beachten Sie also, dass entweder "berechnete Auswertung" der Effizienz von Abfrageoperatoren entspricht und ohne "in Kombination" mit anderen Abfrageoperatorbedingungen, die auf einen "Index" zugreifen können, ein "vollständiger Sammlungsscan" eingeleitet wird.
Aber das Gesamtergebnis ist sicherlich effizienter, als alle übereinstimmenden Elemente an die erste Abfragebedingung zurückzugeben und sie dann am Cursor "nach" der Rückkehr aus der Datenbank zurückzuweisen.
Siehe auch Dokumentation für $arrayElemAt
, $indexOfArray
, $lt
und Array.find()
für JavaScript