sql >> Base de Datos >  >> NoSQL >> MongoDB

Crear un índice comodín en MongoDB

Hay varias formas de crear un índice en MongoDB y, a partir de MongoDB 4.2, podemos crear índices comodín.

Se puede pensar en un índice comodín como una especie de filtro que coincide automáticamente con cualquier campo, subdocumento o matriz en una colección y luego indexa esas coincidencias.

Esto puede ser útil si sus documentos contienen datos no estructurados con diferentes campos en diferentes jerarquías. En tales casos, no hay forma de predecir cuál debería ser el índice, porque no sabe qué datos habrá en cada documento.

Los índices comodín pueden ser útiles con tales datos no estructurados, porque indexan todos los valores escalares del campo, recurriendo automáticamente a cualquier subdocumento o matriz e indexando todos los campos escalares en el subdocumento/matriz.

Colección de ejemplo

Los índices comodín no son para todas las colecciones. Solo crearía un índice comodín en ciertas colecciones con documentos que contienen datos no estructurados con diferentes campos en diferentes jerarquías.

A continuación se muestra un ejemplo de una colección llamada pets que podría ser un buen candidato para un índice comodín:

{
	"_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 uno de los 3 documentos de esta colección tiene un details campo, pero contienen diferentes campos dentro de ese campo. No es consistente. Esto normalmente dificultaría la creación de un índice, porque no sabemos qué campos habrá en cada documento. Probablemente necesitaríamos crear múltiples índices, después de un análisis cuidadoso de las posibles estructuras del documento.

Afortunadamente podemos crear un índice comodín.

Pero primero, echemos un vistazo a cómo se vería un plan de consulta al consultar uno de esos campos. Imagina que queremos saber qué perro obtuvo el premio al “Perro más rápido” en el maratón de Nueva York. Podríamos hacer lo siguiente:

db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } )

Y si quisiéramos verificar el plan de consulta, podríamos agregar explain() hasta el final:

db.pets.find( { "details.awards.New York Marathon" : "Fastest Dog" } ).explain()

Que devuelve lo siguiente:

{
	"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
}

Lo que nos dice que iba a hacer un escaneo de colección (COLLSCAN), lo que significa que tiene que escanear todos los documentos en busca del campo.

Crear un índice comodín

Este es un ejemplo de cómo crear un índice comodín para la colección anterior.

db.pets.createIndex({ "details.$**": 1 });

Salida:

{
	"createdCollectionAutomatically" : false,
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"ok" : 1
}

Eso es todo. Se ha creado el índice comodín.

Para crear el índice comodín, usamos el nombre del campo en el que queríamos crear el índice (en este caso, los details campo), luego lo añadimos con un punto (. ), y luego la parte importante, el $** parte.

El $** especifica que se debe crear un índice comodín a partir de este campo y todos sus subdocumentos.

Anteponer el $** con details limita el alcance del índice comodín a solo los details campo.

Ahora volvamos a revisar el plan de consulta para la 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
}

Esta vez, el escaneo de colección (COLLSCAN) ha sido reemplazado por un escaneo de índice (IXSCAN) en nuestro índice comodín recién creado.

Cada campo dentro de nuestros details El campo se ha indexado como una ruta/valor y hay una entrada en el índice para cada campo en la jerarquía. Donde el valor del campo es un subdocumento (como nuestro. awards campo), la indexación descendió al subdocumento y repitió el proceso.

Creación de un índice comodín en todas las rutas de campo

En el ejemplo anterior, creamos un índice comodín en una única ruta de campo. Es posible crear un índice comodín en todas las rutas de los campos simplemente usando el $** sin prefijarlo con un campo.

Por ejemplo, podríamos haber hecho esto:

db.pets.createIndex({ "$**": 1 });

Eso habría creado un índice comodín en todas las rutas de campo.

En realidad, eso no es del todo cierto. De forma predeterminada, los índices comodín no se crean en el _id campo. Para incluir el _id campo, deberá incluirlo en una wildcardProjection documento.

¿No puede crear índices comodín? Compruebe esta configuración.

El mongod featureCompatibilityVersion debe ser al menos 4.2 para crear índices comodín.

Puede verificar esta configuración con el siguiente código:

db.adminCommand( 
    { 
        getParameter: 1, 
        featureCompatibilityVersion: 1 
    } 
)

Puede configurarlo usando setFeatureCompatibilityVersion comando:

db.adminCommand( { setFeatureCompatibilityVersion: "4.4" } )

setFeatureCompatibilityVersion el comando debe ejecutarse en el admin base de datos.