Det finns flera sätt att skapa ett index i MongoDB, och från MongoDB 4.2 kan vi skapa jokerteckenindex.
Ett jokerteckenindex kan ses som ett slags filter som automatiskt matchar alla fält, underdokument eller matriser i en samling och sedan indexerar dessa matchningar.
Detta kan vara användbart om dina dokument innehåller ostrukturerade data med olika fält i olika hierarkier. I sådana fall finns det inget sätt att förutsäga vad indexet ska vara, eftersom du inte vet vilken data som kommer att finnas i varje dokument.
Jokerteckenindex kan vara användbara med sådan ostrukturerad data, eftersom de indexerar alla skalära värden i fältet, automatiskt återkommer i alla underdokument eller arrayer och indexerar alla skalära fält i underdokumentet/arrayen.
Exempelsamling
Jokertecken-index är inte för varje samling. Du skulle bara skapa ett jokertecken på vissa samlingar med dokument som innehåller ostrukturerade data med olika fält i olika hierarkier.
Nedan är ett exempel på en samling som heter pets
som kan vara en bra kandidat för ett jokertecken:
{
"_id" : 1,
"name" : "Wag",
"details" : {
"type" : "Dog",
"weight" : 20,
"awards" : {
"Florida Dog Awards" : "Top Dog",
"New York Marathon" : "Fastest Dog",
"Sumo 2020" : "Biggest Dog"
}
}
}
{
"_id" : 2,
"name" : "Fetch",
"details" : {
"born" : ISODate("2020-06-22T14:00:00Z"),
"color" : "Black"
}
}
{
"_id" : 3,
"name" : "Scratch",
"details" : {
"eats" : [
"Mouse Porridge",
"Bird Soup",
"Caviar"
],
"type" : "Cat",
"born" : ISODate("2020-12-19T14:00:00Z")
}
}
Vart och ett av de tre dokumenten i denna samling har en details
fältet, men de innehåller olika fält inom det fältet. Det är inte konsekvent. Detta skulle normalt göra det svårt att skapa ett index, eftersom vi inte vet vilka fält som kommer att finnas i varje dokument. Vi skulle förmodligen behöva skapa flera index, efter noggrann analys av de möjliga dokumentstrukturerna.
Lyckligtvis kan vi skapa ett jokertecken.
Men först, låt oss ta en titt på hur en frågeplan kan se ut när du frågar ett av dessa fält. Föreställ dig att vi vill ta reda på vilken hund som fick priset "Snabbaste hund" vid New York Marathon. Vi skulle kunna göra följande:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } )
Och om vi vill kontrollera frågeplanen kan vi lägga till explain()
till slutet:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()
Vilket returnerar följande:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "PetHotel.pets",
"indexFilterSet" : false,
"parsedQuery" : {
"details.awards.New York Marathon" : {
"$eq" : "Fastest Dog"
}
},
"queryHash" : "EC0D5185",
"planCacheKey" : "EC0D5185",
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"details.awards.New York Marathon" : {
"$eq" : "Fastest Dog"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"ok" : 1
}
Vilket talar om för oss att den skulle göra en samlingsskanning (COLLSCAN), vilket innebär att den måste skanna igenom varje dokument som letar efter fältet.
Skapa ett jokerteckenindex
Här är ett exempel på hur du skapar ett jokertecken för ovanstående samling.
db.pets.createIndex({ "details.$**": 1 });
Utdata:
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
Det är allt. Jokerteckenindexet har skapats.
För att skapa jokerteckenindexet använde vi fältnamnet som vi ville skapa indexet på (i det här fallet details
fältet), sedan lade vi till det med en punkt (.
), och sedan den viktiga delen, $**
del.
$**
anger att ett jokertecken ska skapas från detta fält och alla dess underdokument.
Prefixet $**
med details
begränsar jokerteckenindexets omfattning till bara details
fältet.
Låt oss nu kontrollera frågeplanen för den ovannämnda frågan:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()
Resultat:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "PetHotel.pets",
"indexFilterSet" : false,
"parsedQuery" : {
"details.awards.New York Marathon" : {
"$eq" : "Fastest Dog"
}
},
"queryHash" : "EC0D5185",
"planCacheKey" : "7DFA23ED",
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"$_path" : 1,
"details.awards.New York Marathon" : 1
},
"indexName" : "details.$**_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"$_path" : [ ],
"details.awards.New York Marathon" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"$_path" : [
"[\"details.awards.New York Marathon\", \"details.awards.New York Marathon\"]"
],
"details.awards.New York Marathon" : [
"[\"Fastest Dog\", \"Fastest Dog\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"ok" : 1
}
Den här gången har samlingsskanningen (COLLSCAN) ersatts av en indexskanning (IXSCAN) på vårt nyskapade jokerteckenindex.
Varje fält i våra details
fältet har indexerats som en sökväg/värde, och det finns en post i indexet för varje fält i hierarkin. Där fältvärdet är ett underdokument (som våra. awards
). fältet), har indexeringen gått ner i underdokumentet och upprepat processen.
Skapa ett jokerteckenindex på alla fältsökvägar
I det föregående exemplet skapade vi ett jokertecken på en enda fältsökväg. Det är möjligt att skapa ett jokertecken på alla fältsökvägar helt enkelt genom att använda $**
utan att prefixet det med ett fält.
Vi kunde till exempel ha gjort detta:
db.pets.createIndex({ "$**": 1 });
Det skulle ha skapat ett jokertecken på alla fältsökvägar.
Egentligen är det inte riktigt sant. Som standard skapas inte jokerteckenindex på _id
fält. För att inkludera _id
fältet måste du inkludera det i en wildcardProjection
dokument.
Kan du inte skapa jokertecken? Kontrollera den här inställningen.
mongod
featureCompatibilityVersion
måste vara minst 4.2
för att skapa jokertecken.
Du kan kontrollera denna inställning med följande kod:
db.adminCommand(
{
getParameter: 1,
featureCompatibilityVersion: 1
}
)
Du kan ställa in den med setFeatureCompatibilityVersion
kommando:
db.adminCommand( { setFeatureCompatibilityVersion: "4.4" } )
setFeatureCompatibilityVersion
kommandot måste köras i admin
databas.