Cuando crea un índice comodín en MongoDB, tiene la opción de especificar un solo campo, todos los campos o solo algunos.
Puedes usar la wildcardProjection
parámetro para incluir o excluir rutas de campo específicas del índice comodín. Este artículo presenta un ejemplo de cómo incluir campos específicos en el índice de comodines.
Documento de ejemplo
Supongamos que tenemos una colección llamada pets
con los siguientes documentos:
{ "_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") } }
Podríamos crear un índice comodín en toda la colección, pero solo incluir los campos que queremos.
Crear el índice
He aquí un ejemplo:
db.pets.createIndex(
{ "$**" : 1 },
{
"wildcardProjection" : {
"details.type" : 1,
"details.born" : 1
}
}
)
Salida:
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
El { "$**" : 1 }
parte es lo que crea el índice comodín y la wildcardProjection
parte es la parte que especifica qué campos incluir. En este caso hemos incluido el details.type
y el campo details.born
campo. Dándoles un valor de 1
los incluye explícitamente en el índice.
Ver el índice
Podemos ver los índices de la colección llamando a getIndexes()
método:
db.pets.getIndexes()
Resultado:
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" }, { "v" : 2, "key" : { "$**" : 1 }, "name" : "$**_1", "wildcardProjection" : { "details.type" : 1, "details.born" : 1 } } ]
Podemos ver que hay dos índices.
- El primer índice está en
_id
campo. Esto se creó cuando se creó la colección (MongoDB crea un índice único en el campo _id durante la creación de una colección). - El segundo índice es nuestro índice comodín. Podemos ver que se ha nombrado automáticamente
$**_1
, e incluye los campos que especificamos.
Prueba el índice
También podemos ejecutar algunas consultas para ver si nuestro índice se utilizará o no.
En teoría, la siguiente consulta debería usar el índice:
db.pets.find( { "details.type" : "Dog" } )
Para probar esto, podemos agregar explain()
método para ver el plan de consulta:
db.pets.find( { "details.type" : "Dog" } ).explain()
Resultado:
{ "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 }
Podemos ver que usó un escaneo de índice (IXSCAN) en nuestro índice.
En contraste con esto, esto es lo que sucede cuando ejecutamos una consulta en un campo que no incluido en el índice:
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" : "EC0D5185", "winningPlan" : { "stage" : "COLLSCAN", "filter" : { "details.awards.New York Marathon" : { "$eq" : "Fastest Dog" } }, "direction" : "forward" }, "rejectedPlans" : [ ] }, "ok" : 1 }
En este caso, realizó un análisis de la colección (COLLSCAN), por lo que, como era de esperar, no utilizó el índice.