MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Créer un index générique dans MongoDB

Il existe plusieurs façons de créer un index dans MongoDB, et à partir de MongoDB 4.2, nous pouvons créer des index génériques.

Un index générique peut être considéré comme une sorte de filtre qui correspond automatiquement à n'importe quel champ, sous-document ou tableau d'une collection, puis indexe ces correspondances.

Cela peut être utile si vos documents contiennent des données non structurées avec différents champs dans différentes hiérarchies. Dans de tels cas, il n'y a aucun moyen de prédire ce que devrait être l'index, car vous ne savez pas quelles données seront dans chaque document.

Les index génériques peuvent être utiles avec de telles données non structurées, car ils indexent toutes les valeurs scalaires du champ, se récursant automatiquement dans tous les sous-documents ou tableaux et indexant tous les champs scalaires dans le sous-document/tableau.

Exemple de collecte

Les index génériques ne sont pas pour toutes les collections. Vous ne créeriez un index générique que sur certaines collections avec des documents contenant des données non structurées avec différents champs dans différentes hiérarchies.

Vous trouverez ci-dessous un exemple de collection appelée pets qui pourrait être un bon candidat pour un index générique :

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

Chacun des 3 documents de cette collection a un details champ, mais ils contiennent des champs différents dans ce champ. Ce n'est pas cohérent. Cela compliquerait normalement la création d'un index, car nous ne savons pas quels champs se trouveront dans chaque document. Nous aurions probablement besoin de créer plusieurs index, après une analyse minutieuse des structures de documents possibles.

Heureusement, nous pouvons créer un index générique.

Mais d'abord, regardons à quoi pourrait ressembler un plan de requête lors de l'interrogation de l'un de ces champs. Imaginez que nous voulions savoir quel chien a reçu le prix du « chien le plus rapide » au marathon de New York. Nous pourrions faire ce qui suit :

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

Et si nous voulions vérifier le plan de requête, nous pourrions ajouter explain() jusqu'à la fin :

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

Ce qui renvoie ce qui suit :

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

Ce qui nous dit qu'il allait faire une analyse de collection (COLLSCAN), ce qui signifie qu'il doit parcourir chaque document à la recherche du champ.

Créer un index générique

Voici un exemple de création d'un index générique pour la collection ci-dessus.

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

Sortie :

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

C'est ça. L'index générique a été créé.

Pour créer l'index générique, nous avons utilisé le nom du champ sur lequel nous voulions créer l'index (dans ce cas, les details champ), puis nous l'avons ajouté avec un point (. ), puis la partie importante, le $** partie.

Le $** spécifie qu'un index générique doit être créé à partir de ce champ et de tous ses sous-documents.

Préfixer le $** avec details limite la portée de l'index générique aux seuls details champ.

Revérifions maintenant le plan de requête pour la requête susmentionnée :

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

Résultat :

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

Cette fois, l'analyse de collection (COLLSCAN) a été remplacée par une analyse d'index (IXSCAN) sur notre index générique nouvellement créé.

Chaque champ de nos details a été indexé en tant que chemin/valeur, et il existe une entrée dans l'index pour chaque champ de la hiérarchie. Où la valeur du champ est un sous-document (comme our. awards champ), l'indexation est descendue dans le sous-document et a répété le processus.

Création d'un index générique sur tous les chemins de champ

Dans l'exemple précédent, nous avons créé un index générique sur un seul chemin de champ. Il est possible de créer un index générique sur tous les chemins de champs simplement en utilisant le $** sans le préfixer avec un champ.

Par exemple, nous aurions pu faire ceci :

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

Cela aurait créé un index générique sur tous les chemins de champ.

En fait, ce n'est pas tout à fait vrai. Par défaut, les index génériques ne sont pas créés sur le _id domaine. Pour inclure le _id champ, vous devrez l'inclure dans un wildcardProjection document.

Impossible de créer des index génériques ? Vérifiez ce paramètre.

Le mongod featureCompatibilityVersion doit être au moins 4.2 pour créer des index génériques.

Vous pouvez vérifier ce paramètre avec le code suivant :

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

Vous pouvez le définir à l'aide de setFeatureCompatibilityVersion commande :

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

Le setFeatureCompatibilityVersion la commande doit être exécutée dans admin base de données.