Existem várias maneiras de criar um índice no MongoDB e, a partir do MongoDB 4.2, podemos criar índices curinga.
Um índice curinga pode ser considerado um tipo de filtro que corresponde automaticamente a qualquer campo, subdocumento ou array em uma coleção e, em seguida, indexa essas correspondências.
Isso pode ser útil se seus documentos contiverem dados não estruturados com campos diferentes em hierarquias diferentes. Nesses casos, não há como prever qual deve ser o índice, porque você não sabe quais dados estarão em cada documento.
Índices curinga podem ser úteis com esses dados não estruturados, porque indexam todos os valores escalares do campo, automaticamente recursivamente em quaisquer subdocumentos ou matrizes e indexando todos os campos escalares no subdocumento/matriz.
Coleção de exemplo
Os índices curinga não são para todas as coleções. Você só criaria um índice curinga em determinadas coleções com documentos que contêm dados não estruturados com campos diferentes em hierarquias diferentes.
Abaixo está um exemplo de uma coleção chamada
pets
que pode ser um bom candidato para um índice curinga:{
"_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")
}
}
Cada um dos 3 documentos nesta coleção tem um
details
campo, mas eles contêm campos diferentes dentro desse campo. Não é consistente. Isso normalmente dificultaria a criação de um índice, porque não sabemos quais campos estarão em cada documento. Provavelmente precisaríamos criar vários índices, após uma análise cuidadosa das possíveis estruturas de documentos. Felizmente, podemos criar um índice curinga.
Mas primeiro, vamos dar uma olhada na aparência de um plano de consulta ao consultar um desses campos. Imagine que queremos descobrir qual cachorro recebeu o prêmio de “Cão Mais Rápido” na Maratona de Nova York. Poderíamos fazer o seguinte:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } )
E se quiséssemos verificar o plano de consulta, poderíamos anexar
explain()
até o fim:db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()
Que retorna o seguinte:
{
"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
}
O que nos diz que ia fazer uma varredura de coleção (COLLSCAN), o que significa que ele precisa varrer todos os documentos procurando o campo.
Criar um índice curinga
Aqui está um exemplo de criação de um índice curinga para a coleção acima.
db.pets.createIndex({ "details.$**": 1 });
Saída:
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
É isso. O índice curinga foi criado.
Para criar o índice curinga, usamos o nome do campo no qual queríamos criar o índice (neste caso, os
details
campo), então anexamos isso com um ponto (.
), e então a parte importante, o $**
papel. O
$**
especifica que um índice curinga deve ser criado a partir desse campo e de todos os seus subdocumentos. Prefixando o
$**
com details
limita o escopo do índice curinga apenas aos details
campo. Agora vamos verificar novamente o plano de consulta para a consulta mencionada:
db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()
Resultado:
{
"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
}
Desta vez, a varredura de coleção (COLLSCAN) foi substituída por uma varredura de índice (IXSCAN) em nosso índice curinga recém-criado.
Cada campo em nossos
details
campo foi indexado como um caminho/valor e há uma entrada no índice para cada campo na hierarquia. Onde o valor do campo é um subdocumento (como nosso. awards
campo), a indexação desceu para o subdocumento e repetiu o processo. Criando um índice curinga em todos os caminhos de campo
No exemplo anterior, criamos um índice curinga em um único caminho de campo. É possível criar um índice curinga em todos os caminhos de campos simplesmente usando o
$**
sem prefixá-lo com um campo. Por exemplo, poderíamos ter feito isso:
db.pets.createIndex({ "$**": 1 });
Isso teria criado um índice curinga em todos os caminhos de campo.
Na verdade, isso não é bem verdade. Por padrão, os índices curinga não são criados no
_id
campo. Para incluir o _id
campo, você precisaria incluí-lo em um wildcardProjection
documento. Não é possível criar índices curinga? Verifique esta configuração.
O
mongod
featureCompatibilityVersion
deve ser pelo menos 4.2
para criar índices curinga. Você pode verificar essa configuração com o seguinte código:
db.adminCommand(
{
getParameter: 1,
featureCompatibilityVersion: 1
}
)
Você pode configurá-lo usando o
setFeatureCompatibilityVersion
comando:db.adminCommand( { setFeatureCompatibilityVersion: "4.4" } )
A
setFeatureCompatibilityVersion
comando precisa ser executado no admin
base de dados.