Als je dat soort beperking in de query wilt, heb je in principe twee opties, afhankelijk van wat je MongoDB-versie ondersteunt:
MongoDB 3.6
Gebruik bij voorkeur $expr
"bovendien" aan alle normale zoekvoorwaarden om daadwerkelijk geldige documenten te selecteren:
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 ]}
]}
]
}
})
Of overeenkomend met de "laatste" voorval:
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 ] }
]}
]}
]
}
})
Eerdere versies
Hetzelfde, maar zonder native operators moet je de JavaScript-evaluatie van
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`
})
Of overeenkomend met de "laatste" voorval:
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`
})
Als je dat nodig had in een aggregatiepijplijn, dan zou je gebruiken $redacteren
en vergelijkbare logica als het eerste voorbeeld:
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"
}
}}
])
Het volstaat te zeggen dat de "vergelijkingslogica" niet echt eigen is aan "query-operatorexpressies" zelf, dus het enige deel dat "optimaal" is kan worden toegepast op een index met behulp van de $all
query-operator in alle gevallen. De essentiële resterende logica is feitelijk van toepassing "na" dat de hoofdexpressie is geëvalueerd en "in aanvulling op" zodat er geen resultaten worden geretourneerd, behalve die welke voldoen aan de expressie met $expr
of $where
.
De basislogica van elk is in wezen het extraheren van de waarde van de "index"
eigenschap van het "eerste" arraylid dat daadwerkelijk overeenkomt met de respectieve waarde in de "waarde"
eigendom. Waar dit "minder dan" is, dan is de voorwaarde waar
en dit voldoet aan het document dat wordt geretourneerd.
Houd er dus rekening mee dat ofwel "berekende evaluatie" overeenkomt met de efficiëntie van query-operators, en zonder te worden gebruikt "in combinatie" van andere query-operatorvoorwaarden die toegang hebben tot een "index", zal een "volledige verzamelingsscan" worden gestart.
Maar het algemene resultaat is zeker efficiënter dan alle overeenkomende items terug te sturen naar de eerste vraagvoorwaarde en ze vervolgens te weigeren op de cursor "na" terugkeer uit de database.
Zie ook documentatie voor $arrayElemAt
, $indexOfArray
, $lt
en Array.find()
voor JavaScript