Когато създавате заместващ индекс в MongoDB, имате възможност да посочите едно поле, всички полета или само някои.
Можете да използвате wildcardProjection
параметър за включване или изключване на конкретни пътеки на полета от заместващия индекс. Тази статия представя пример за включване на конкретни полета в индекса за заместващи знаци.
Примерен документ
Да предположим, че имаме колекция, наречена pets
със следните документи:
{ "_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") } }
Бихме могли да създадем заместващ индекс за цялата колекция, но да включим само полетата, които искаме.
Създайте индекса
Ето един пример:
db.pets.createIndex(
{ "$**" : 1 },
{
"wildcardProjection" : {
"details.type" : 1,
"details.born" : 1
}
}
)
Изход:
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
{ "$**" : 1 }
част е това, което създава заместващия индекс и wildcardProjection
част е частта, която определя кои полета да се включат. В този случай сме включили details.type
полето и details.born
поле. Давайки им стойност от 1
изрично ги включва в индекса.
Преглед на индекса
Можем да видим индексите на колекцията, като извикаме getIndexes()
метод:
db.pets.getIndexes()
Резултат:
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" }, { "v" : 2, "key" : { "$**" : 1 }, "name" : "$**_1", "wildcardProjection" : { "details.type" : 1, "details.born" : 1 } } ]
Виждаме, че има два индекса.
- Първият индекс е на
_id
поле. Това е създадено при създаването на колекцията (MongoDB създава уникален индекс в полето _id по време на създаването на колекция). - Вторият индекс е нашият заместващ индекс. Можем да видим, че автоматично е наречен
$**_1
, и включва полетата, които посочихме.
Тествайте индекса
Можем също да изпълним някои заявки, за да видим дали нашият индекс ще бъде използван или не.
На теория следната заявка трябва да използва индекса:
db.pets.find( { "details.type" : "Dog" } )
За да тестваме това, можем да добавим explain()
метод за преглед на плана на заявката:
db.pets.find( { "details.type" : "Dog" } ).explain()
Резултат:
{ "queryPlanner" : { "plannerVersion" : 1, "namespace" : "PetHotel.pets", "indexFilterSet" : false, "parsedQuery" : { "details.type" : { "$eq" : "Dog" } }, "queryHash" : "F1C5286F", "planCacheKey" : "5326DE93", "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "$_path" : 1, "details.type" : 1 }, "indexName" : "$**_1", "isMultiKey" : false, "multiKeyPaths" : { "$_path" : [ ], "details.type" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "$_path" : [ "[\"details.type\", \"details.type\"]" ], "details.type" : [ "[\"Dog\", \"Dog\"]" ] } } }, "rejectedPlans" : [ ] }, "ok" : 1 }
Можем да видим, че използва индексно сканиране (IXSCAN) на нашия индекс.
За разлика от това, ето какво се случва, когато изпълним заявка в поле, което не включени в индекса:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()
Резултат:
{ "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 }
В този случай той направи сканиране на колекция (COLLSCAN), така че както се очакваше, не използва индекса.