Existuje několik způsobů, jak vytvořit index v MongoDB, a od MongoDB 4.2 můžeme vytvářet indexy zástupných znaků.
Index zástupných znaků lze považovat za druh filtru, který automaticky odpovídá jakémukoli poli, dílčímu dokumentu nebo poli v kolekci a poté tyto shody indexuje.
To může být užitečné, pokud vaše dokumenty obsahují nestrukturovaná data s různými poli v různých hierarchiích. V takových případech neexistuje způsob, jak předpovědět, jaký by měl být index, protože nevíte, jaká data budou v každém dokumentu.
U takových nestrukturovaných dat mohou být užitečné indexy zástupných znaků, protože indexují všechny skalární hodnoty pole, automaticky se opakují do jakýchkoli vnořených dokumentů nebo polí a indexují všechna skalární pole v vnořeném dokumentu/poli.
Ukázková sbírka
Indexy zástupných znaků nejsou pro každou kolekci. Index zástupných znaků byste vytvořili pouze pro určité kolekce s dokumenty, které obsahují nestrukturovaná data s různými poli v různých hierarchiích.
Níže je uveden příklad sbírky nazvané pets
to by mohl být dobrý kandidát na index zástupných znaků:
{
"_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")
}
}
Každý ze 3 dokumentů v této kolekci má details
pole, ale obsahují různá pole v tomto poli. není konzistentní. To by normálně znesnadnilo vytvoření indexu, protože nevíme, jaká pole budou v každém dokumentu. Pravděpodobně bychom po pečlivé analýze možných struktur dokumentů potřebovali vytvořit více indexů.
Naštěstí můžeme vytvořit index zástupných znaků.
Nejprve se však podívejme, jak může vypadat plán dotazů při dotazu na jedno z těchto polí. Představte si, že chceme zjistit, který pes získal ocenění „Nejrychlejší pes“ na newyorském maratonu. Mohli bychom udělat následující:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } )
A pokud bychom chtěli zkontrolovat plán dotazů, mohli bychom připojit explain()
do konce:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()
Což vrátí následující:
{
"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
}
Což nám říká, že se chystá provést skenování sbírky (COLLSCAN), což znamená, že musí prohledat každý dokument a hledat pole.
Vytvořte index zástupných znaků
Zde je příklad vytvoření indexu zástupných znaků pro výše uvedenou kolekci.
db.pets.createIndex({ "details.$**": 1 });
Výstup:
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
A je to. Index zástupných znaků byl vytvořen.
K vytvoření indexu zástupných znaků jsme použili název pole, na kterém jsme chtěli index vytvořit (v tomto případě details
pole), pak jsme to přidali tečkou (.
) a pak důležitá část, $**
část.
$**
určuje, že z tohoto pole a všech jeho vnořených dokumentů by měl být vytvořen index zástupných znaků.
Předpona $**
s details
omezuje rozsah indexu zástupných znaků pouze na details
pole.
Nyní znovu zkontrolujte plán dotazů pro výše uvedený dotaz:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()
Výsledek:
{
"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
}
Tentokrát bylo skenování kolekce (COLLSCAN) nahrazeno skenováním indexu (IXSCAN) na našem nově vytvořeném indexu zástupných znaků.
Každé pole v našich details
pole bylo indexováno jako cesta/hodnota a v indexu je záznam pro každé pole v hierarchii. Kde hodnota pole je vnořený dokument (například naše. awards
pole), indexování sestoupilo do vnořeného dokumentu a proces se opakoval.
Vytvoření indexu zástupných znaků na všech cestách polí
V předchozím příkladu jsme vytvořili index zástupných znaků na cestě jednoho pole. Je možné vytvořit zástupný index na všech cestách polí jednoduše pomocí $**
bez předpony polem.
Mohli jsme například udělat toto:
db.pets.createIndex({ "$**": 1 });
To by vytvořilo zástupný index na všech polních cestách.
Ve skutečnosti to není tak docela pravda. Ve výchozím nastavení se indexy zástupných znaků nevytvářejí na _id
pole. Chcete-li zahrnout _id
pole, budete jej muset zahrnout do wildcardProjection
dokument.
Nemůžete vytvářet indexy zástupných znaků? Zkontrolujte toto nastavení.
mongod
featureCompatibilityVersion
musí být alespoň 4.2
k vytvoření indexů zástupných znaků.
Toto nastavení můžete zkontrolovat pomocí následujícího kódu:
db.adminCommand(
{
getParameter: 1,
featureCompatibilityVersion: 1
}
)
Můžete jej nastavit pomocí setFeatureCompatibilityVersion
příkaz:
db.adminCommand( { setFeatureCompatibilityVersion: "4.4" } )
setFeatureCompatibilityVersion
příkaz je třeba spustit v admin
databáze.