MongoDB har stor understøttelse af arrays og giver en masse fleksibilitet i din dokumenttilstand. For eksempel kan du indlejre arrays i dokumenter og også indlejre dokumenter i arrays osv. Arbejdet med arrays har dog en række gotcha's i MongoDB. I dette indlæg vil vi se på nogle af de problemer, MongoDB har med indekser og arrays.
Multikey-indekser
I MongoDB kan du indeksere et matrixfelt for at oprette en indeksindgang for hvert element i matrixen. Det resulterende indeks kaldes et 'multikey'-indeks. Multikey-indekser kan oprettes over skalære værdier eller indlejrede dokumenter. Se denne dokumentation for flere oplysninger om multikey-indekser.
Multikey-indekser, selvom de er nyttige, har flere begrænsninger:
- Hvis du opretter et sammensat multinøgleindeks, har du mindst ét felt, der er en matrix.
- Et sammensat indeks kan ikke være en shard-nøgle.
- Et sammensat indeks kan ikke være et hashed-indeks.
Et af de mest interessante aspekter ved multikey-indekser er, hvordan indeksgrænser beregnes.
Indeks skærende grænser
Her er, hvordan MongoDB-dokumentationen definerer indeksets skæringsgrænser:
"Grænserne for en indeksscanning definerer de dele af et indeks, der skal søges under en forespørgsel. Når der findes flere prædikater over et indeks, vil MongoDB forsøge at kombinere grænserne for disse prædikater ved enten skæringspunkt eller sammensætning for at producere en scanning med mindre grænser.”
Rangeforespørgsler på arrays
Lad os komme i gang med et simpelt eksempel for at se, hvordan MongoDB beregner indeksgrænser for forespørgsler på arrays. Antag, at vi har følgende tre dokumenter i en samling:
{x:65}{x:35}{x:[12,95]}
Vi udsteder følgende forespørgsel:
db.coll.find({x :{ $gt :22, $lt:55})
Forespørgslen er simpel nok. Du ville forvente, at svaret er {x:35}, men forespørgslen returnerer:
{x:35}{x:[25,95]}
Årsagen kommer fra, hvordan MongoDB håndterer arrays. Det samme element i arrayet behøver ikke at matche begge betingelser; så længe der er et element, der matcher hver betingelse, er det et match. Så i dette tilfælde er grænserne [22, Infinity] og [-Infinity, 55]. Da en 'elemMatch'-operator ikke bruges, bruger MongoDB ikke indekskrydset. MongoDB specificerer ikke, hvilke af disse områder [22, Infinity] eller [-Infinity, 55] der vil blive brugt til udførelse af forespørgslen.
Hvis vi vil bruge indekskrydset, skal vi bruge følgende forespørgsel:
db.coll.find(x :{ $elemMatch:{$gt :22,$lt:55}})
Når du bruger dette, skærer MongoDB indeksgrænserne og bruger [22, 55] som grænser. Som forventet returnerer denne forespørgsel ingen resultater (elemMatch matcher ikke ikke-arrays). Så i det væsentlige er intervalforespørgsler på arrays ret ubrugelige uden $elemMatch-operatoren.
Sammensatte multikey-indekser – blanding af matrix- og ikke-array-felter
Overvej en samling med følgende dokumenter:
{item:35, prices:[250,35]}......{item:106, prices:[1500,65]}
Vi tilføjer et sammensat indeks på denne samling:
db.ensureIndex({vare:1, priser:1});
Lad os nu køre en simpel forespørgsel:
db. saml. find({vare:{$gt:12, $lt:65}});
Forespørgslen ser simpel nok ud, da vi bruger et ikke-array-element med et fast interval. Jeg forventer, at indekset skærer grænser er noget i stil med element:[[12,65] ] for forespørgslen, men hvis du kører en forklaring, vil du se dette:
"indexBounds" :{"item" :[ [ -Infinity, 65 ] ],"prices" :[ [ { "$minElement" :1 }, { "$maxElement" :1 } ] ]},Årsagen er, at MongoDB registrerer, at dette er et multikey-indeks, og ikke behandler indeksgrænseskrydset, uanset at din forespørgsel ikke bruger nogen array-felter. Moralen i historien er, at når du blander array- og ikke-array-felter i et indeks, skal du altid holde øje med grænserne for indeksets skæringspunkt. Odds er, at det ikke er effektivt.