For MongoDB 3.6 og nyere:
$expr
operatoren tillader brugen af aggregeringsudtryk i forespørgselssproget, så du kan udnytte brugen af $strLenCP
operatør for at kontrollere længden af strengen som følger:
db.usercollection.find({
"name": { "$exists": true },
"$expr": { "$gt": [ { "$strLenCP": "$name" }, 40 ] }
})
For MongoDB 3.4 og nyere:
Du kan også bruge aggregeringsrammen med $redact
pipeline-operatør, der giver dig mulighed for at behandle den logiske betingelse med $cond
operatør og bruger de særlige operationer $$KEEP
at "beholde" dokumentet, hvor den logiske betingelse er sand eller $$PRUNE
for at "fjerne" dokumentet, hvor betingelsen var falsk.
Denne operation ligner at have et $project
pipeline, der vælger felterne i samlingen og opretter et nyt felt, der indeholder resultatet fra den logiske betingelsesforespørgsel og derefter en efterfølgende $match
, bortset fra at $redact
bruger et enkelt pipeline-trin, som er mere effektivt.
Hvad angår den logiske betingelse, er der strengaggregeringsoperatorer, som du kan bruge $strLenCP
operatør for at kontrollere længden af strengen. Hvis længden er $gt
en specificeret værdi, så er dette et sandt match, og dokumentet "bevares". Ellers "beskæres" og kasseres.
Overvej at køre følgende samlede operation, som demonstrerer ovenstående koncept:
db.usercollection.aggregate([
{ "$match": { "name": { "$exists": true } } },
{
"$redact": {
"$cond": [
{ "$gt": [ { "$strLenCP": "$name" }, 40] },
"$$KEEP",
"$$PRUNE"
]
}
},
{ "$limit": 2 }
])
Hvis du bruger $where
, prøv din forespørgsel uden de omsluttende parenteser:
db.usercollection.find({$where: "this.name.length > 40"}).limit(2);
En bedre forespørgsel ville være at kontrollere feltets eksistens og derefter kontrollere længden:
db.usercollection.find({name: {$type: 2}, $where: "this.name.length > 40"}).limit(2);
eller:
db.usercollection.find({name: {$exists: true}, $where: "this.name.length >
40"}).limit(2);
MongoDB evaluerer ikke-$where
forespørgselsoperationer før $where
udtryk og ikke-$where
forespørgselsudsagn kan bruge et indeks. En meget bedre ydeevne er at gemme længden af strengen som et andet felt, og så kan du indeksere eller søge på den; anvender $where
vil være meget langsommere i forhold til det. Det anbefales at bruge JavaScript-udtryk og $where
operatør som en sidste udvej, når du ikke kan strukturere dataene på nogen anden måde, eller når du har at gøre med en lille delmængde af data.
En anderledes og hurtigere tilgang, der undgår brugen af $where
operatoren er $regex
operatør. Overvej følgende mønster, som søger efter
db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2);
Bemærk - Fra dokumenterne :
Hvis der findes et indeks for feltet, så matcher MongoDB det regulære udtryk mod værdierne i indekset, hvilket kan være hurtigere end en samlingsscanning. Yderligere optimering kan forekomme, hvis det regulære udtryk er et "præfiksudtryk", hvilket betyder, at alle potentialmatches starter med den samme streng. Dette gør det muligt for MongoDB at konstruere et "interval" fra det præfiks og kun matche de værdier fra indekset, der falder inden for det interval.
Et regulært udtryk er et "præfiksudtryk", hvis det starter med acaret (^)
eller et venstre anker (\A)
, efterfulgt af en række simple symboler. For eksempel regex /^abc.*/
vil blive optimeret ved kun at matche værdierne fra indekset, der starter med abc
.
Derudover mens /^a/, /^a.*/,
og /^a.*$/
matcher ækvivalente strenge, de har forskellige præstationskarakteristika. Alle disse udtryk bruger et indeks, hvis der findes et passende indeks; dog /^a.*/
og /^a.*$/
er langsommere. /^a/
kan stoppe scanningen efter at have matchet præfikset.