Overview
En esta guía, puedes aprender cómo utilizar intercalaciones con MongoDB para ordenar los resultados de tu consulta u operación de agregación por valores de strings. Una intercalación es un conjunto de reglas de ordenamiento y coincidencia de caracteres que se aplican a un idioma y localización específicos.
Puedes obtener más información sobre las intercalaciones en las siguientes secciones de esta guía:
Importante
Proyecto Reactor librería
Esta guía usa la librería Proyecto Reactor para consumir instancias Publisher devueltas por los métodos del driver Reactive Streams de Java. Para obtener más información sobre la biblioteca Project Reactor y cómo utilizarla, consulta Primeros pasos en la documentación de Reactor. Para obtener más información sobre cómo utilizamos los métodos de la librería Project Reactor en esta guía, consulta la guía Guardar datos en MongoDB.
Intercalaciones en MongoDB
MongoDB ordena las cadenas utilizando intercalación binaria de forma predeterminada. La intercalación binaria utiliza los valores de caracteres del estándar ASCII para comparar y ordenar cadenas. Ciertos lenguajes y localizaciones tienen convenciones específicas de ordenamiento de caracteres que difieren de los valores de caracteres ASCII.
Por ejemplo, en el francés canadiense, el carácter acentuado más a la derecha (diacrítico) determina el orden de las cadenas cuando todos los caracteres anteriores son iguales. Considera las siguientes palabras en francés canadiense:
manta
coté
côte
côté
Cuando se utiliza una intercalación binaria, MongoDB los ordena en el siguiente orden:
cote coté côte côté
Cuando se utiliza la intercalación de francés canadiense, MongoDB los ordena en el siguiente orden:
cote côte coté côté
Cómo especificar intercalaciones
MongoDB admite intercalaciones en la mayoría de las operaciones CRUD y agregaciones. Para obtener una lista completa de las operaciones compatibles, consulte la sección «Operaciones que admiten intercalaciones» en el manual del servidor MongoDB.
Puedes especificar el código de localización y variante opcional en el siguiente formato de string:
"<locale code>@collation=<variant code>"
El siguiente ejemplo especifica el código de configuración regional "de" y el código de variante "phonebook":
"de@collation=phonebook"
Si no especifica una variante, utilice únicamente el código de configuración regional.
Para obtener una lista completa de las configuraciones regionales compatibles, consulte Idiomas y configuraciones regionales compatibles en el manual del servidor MongoDB.
Las siguientes secciones muestran diferentes maneras de aplicar intercalaciones en MongoDB:
Colección
Solo se puede establecer una intercalación predeterminada para una colección durante su creación. Sin embargo, se puede especificar una intercalación en un nuevo índice de una colección existente. Todas las operaciones compatibles que analizan la colección aplican la intercalación predeterminada. Consulte la sección Índice de esta guía para obtener más información.
El siguiente ejemplo muestra cómo especificar la intercalación de configuración regional "en_US" al crear una nueva colección llamada items:
Mono.from(database.createCollection( "items", new CreateCollectionOptions().collation( Collation.builder().locale("en_US").build()))) .block();
Para comprobar si creó la intercalación correctamente, obtenga una lista de los índices en esa colección de la siguiente manera:
List<Document> indexes = Flux.from(itemsCollection.listIndexes()) .collectList().block(); if (indexes != null) { indexes.forEach(idx -> System.out.println(idx.toJson())); }
La salida del código anterior debe contener lo siguiente:
{ ... "collation": { "locale": "en_US", ... } ... }
Index
Al crear un nuevo índice en una colección, puede especificar una intercalación. El índice almacena los documentos en el orden especificado, lo que elimina la necesidad de ordenarlos en memoria durante las consultas. Para usar el índice, la operación debe utilizar la misma intercalación que la especificada en el índice y estar cubierta por este.
El siguiente ejemplo muestra cómo crear un índice en el campo "nombre" con la intercalación de configuración regional "en_US" en orden ascendente:
IndexOptions idxOptions = new IndexOptions(); idxOptions.collation(Collation.builder().locale("en_US").build()); Mono.from(itemsCollection.createIndex( Indexes.ascending("name"), idxOptions)).block();
Para comprobar si creó la intercalación correctamente, obtenga una lista de los índices en esa colección de la siguiente manera:
List<Document> indexes = Flux.from(itemsCollection.listIndexes()) .collectList().block(); if (indexes != null) { indexes.forEach(idx -> System.out.println(idx.toJson())); }
La salida del código anterior debe contener lo siguiente:
{ ... "collation": { "locale": "en_US", ... } ... }
El siguiente ejemplo muestra una operación que especifica la misma intercalación y está cubierta por el índice creado en el ejemplo anterior:
FindPublisher<Document> indexPublisher = itemsCollection.find() .collation(Collation.builder().locale("en_US").build()) .sort(Sorts.ascending("name")); Flux.from(indexPublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
Operación
Puedes anular la intercalación predeterminada pasando una nueva intercalación a una operación compatible. Sin embargo, sin un índice, la consulta realiza una ordenación en memoria, lo que resulta más lento que usar una intercalación indexada. Para obtener más información sobre las desventajas de las operaciones de ordenación no cubiertas por un índice,consulta «Usar índices para ordenar los resultados de las consultas» en el manual de MongoDB Server.
El siguiente ejemplo muestra una operación de consulta con las siguientes características:
La consulta especifica la intercalación islandesa (
"is"). Dado que esta difiere de la intercalación del índice, la consulta no utiliza el índice y, en su lugar, realiza una ordenación en memoria.
FindPublisher<Document> customPublisher = itemsCollection.find() .collation(Collation.builder().locale("is").build()) .sort(Sorts.ascending("name")); Flux.from(customPublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
Tipos de índice que no admiten intercalaciones
La mayoría de los tipos de índices de MongoDB admiten intercalación. Sin embargo, los siguientes tipos solo admiten comparación binaria y no admiten intercalación:
Opciones de intercalación
Esta sección abarca diversas opciones de intercalación y cómo especificarlas para refinar aún más el comportamiento de intercalación y comparación.
Opción de intercalación | Descripción |
|---|---|
localización | Obligatorio. El código de configuración regional de la UCI para el idioma y la variante. |
Hacia atrás | Especifica si se deben considerar primero los diacríticos desde el final de la cadena. |
Sensibilidad a mayúsculas y minúsculas | Especifica si se deben considerar las mayúsculas y minúsculas como valores diferentes. |
Alternativo | Especifica si se deben tener en cuenta los espacios y la puntuación. |
Primero el caso | Especifica si se deben considerar primero las mayúsculas o las minúsculas. |
Variable máxima | Especifica si se deben ignorar los espacios en blanco o tanto los espacios en blanco como la puntuación. Esta configuración solo es válida cuando la configuración alternativa es "shifted". |
Fuerza | Especifica el nivel de comparación de la UCI. El valor predeterminado es "terciario". Para obtener más información sobre cada nivel, consulte Niveles de comparación de la UCI. |
Normalización | Especifica si se debe realizar la normalización Unicode en el texto según sea necesario. Para obtener más información sobre la normalización Unicode, consulte Formularios de normalización Unicode. |
Ordenación numérica | Especifica si se deben ordenar los números según su valor numérico en lugar de según el orden de intercalación. |
Puede utilizar la clase Collation.Builder para especificar valores para las opciones de intercalación anteriores. Llame al método build() para construir un objeto Collation como se muestra en el siguiente ejemplo:
Collation.builder() .caseLevel(true) .collationAlternate(CollationAlternate.SHIFTED) .collationCaseFirst(CollationCaseFirst.UPPER) .collationMaxVariable(CollationMaxVariable.SPACE) .collationStrength(CollationStrength.SECONDARY) .locale("en_US") .normalization(false) .numericOrdering(true) .build();
Para obtener más información sobre los métodos y parámetros correspondientes, consulte la documentación de la API de Collation.Builder.
Ejemplos de intercalación
Esta sección contiene ejemplos de cómo usar operaciones de MongoDB que admiten intercalaciones. Para cada ejemplo, suponga que comienza con la siguiente colección de documentos:
{ "_id" : 1, "first_name" : "Klara" } { "_id" : 2, "first_name" : "Gunter" } { "_id" : 3, "first_name" : "Günter" } { "_id" : 4, "first_name" : "Jürgen" } { "_id" : 5, "first_name" : "Hannah" }
Los siguientes ejemplos utilizan la intercalación "de@collation=phonebook" con variantes de configuración regional. La parte "de" de la intercalación especifica la configuración regional alemana y la parte "collation=phonebook" especifica una variante. La intercalación "de" contiene reglas para priorizar los nombres propios, identificados por la capitalización de la primera letra. En la variante "collation=phonebook", los caracteres con diéresis se ordenan antes que los caracteres idénticos sin ella, en orden ascendente.
find() and sort() Example
El siguiente ejemplo muestra cómo aplicar una intercalación al recuperar resultados ordenados de una colección. Para realizar esta operación, llame al método find() en la colección de ejemplo y encadene los métodos collation() y sort() para especificar el orden en que desea recibir los resultados.
FindPublisher<Document> findPublisher = phonebookCollection.find() .collation(Collation.builder() .locale("de@collation=phonebook").build()) .sort(Sorts.ascending("first_name")); Flux.from(findPublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
Cuando realizas esta operación en la colección de ejemplo, la salida se asemeja a la siguiente:
{"_id": 3, "first_name": "Günter"} {"_id": 2, "first_name": "Gunter"} {"_id": 5, "first_name": "Hannah"} {"_id": 4, "first_name": "Jürgen"} {"_id": 1, "first_name": "Klara"}
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Ejemplo de findOneAndUpdate()
El siguiente ejemplo especifica una intercalación en una operación findOneAndUpdate() instanciando un objeto FindOneAndUpdateOptions y pasándolo como parámetro. El ejemplo realiza las siguientes operaciones:
Recupera el primer documento de la colección de ejemplos que precede a "Gunter" en orden ascendente.
Establece opciones para la operación, incluida la intercalación
"de@collation=phonebook".Agrega un nuevo campo "verificado" con el valor "verdadero".
Recupera e imprime el documento actualizado.
Document updatedDoc = Mono.from( phonebookCollection.findOneAndUpdate( Filters.lt("first_name", "Gunter"), Updates.set("verified", true), new FindOneAndUpdateOptions() .collation(Collation.builder() .locale("de@collation=phonebook") .build()) .sort(Sorts.ascending("first_name")) .returnDocument(ReturnDocument.AFTER))) .block(); if (updatedDoc != null) { System.out.println("Updated document: " + updatedDoc.toJson()); }
Dado que "Günter" está léxicamente antes que "Gunter" utilizando la intercalación de@collation=phonebook en orden ascendente, la operación precedente devuelve el siguiente documento:
Updated document: {"_id": 3, "first_name": "Günter", "verified": true}
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Ejemplo de findOneAndDelete()
El siguiente ejemplo especifica una intercalación de orden numérico en una operación findOneAndDelete() mediante la creación de una instancia de un objeto FindOneAndDeleteOptions y su paso como parámetro. La colección contiene los siguientes documentos:
{ "_id" : 1, "a" : "16 apples" } { "_id" : 2, "a" : "84 oranges" } { "_id" : 3, "a" : "179 bananas" }
La intercalación establece la opción locale en "en" y la opción numericOrdering en "verdadero" para ordenar las cadenas según su valor numérico.
Document deletedDoc = Mono.from( numericalCollection.findOneAndDelete( Filters.gt("a", "100"), new FindOneAndDeleteOptions() .collation(Collation.builder() .locale("en") .numericOrdering(true) .build()) .sort(Sorts.ascending("a")))) .block(); if (deletedDoc != null) { System.out.println("Deleted document: " + deletedDoc.toJson()); }
Después de ejecutar la operación anterior, el resultado se asemeja a lo siguiente:
Deleted document: {"_id": 3, "a": "179 bananas"}
El valor numérico de la cadena "179" es mayor que 100, por lo que el documento anterior es la única coincidencia. Sin orden numérico, la intercalación binaria ordena "100" antes que "16", "84" y "179", por lo que el filtro coincide con todos los documentos.
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Ejemplo de agregación
El siguiente ejemplo muestra cómo especificar una intercalación en una operación de agregación. Para realizar una agregación, llame al método aggregate() en un objeto MongoCollection.
Para especificar una intercalación para una operación de agregación, llame al método collation() en el AggregatePublisher devuelto por la operación de agregación. Especifique una etapa de agregación de ordenación en su canalización para aplicar la intercalación.
El siguiente ejemplo construye una canalización de agregación en la colección de ejemplo y aplica una intercalación especificando lo siguiente:
Una etapa de agregación de grupo que utiliza
Aggregates.group()para identificar cada documento por el campofirst_namey usar ese valor como el_iddel resultado.Un acumulador en la etapa de grupo para sumar el número de instancias de valores coincidentes en el campo
first_name.Una ordenación ascendente en el campo
_idde los documentos de salida.Un objeto de intercalación que especifica la configuración regional alemana y una intensidad de intercalación que ignora los acentos y las diéresis.
Bson groupStage = Aggregates.group( "$first_name", Accumulators.sum("nameCount", 1)); Bson sortStage = Aggregates.sort(Sorts.ascending("_id")); AggregatePublisher<Document> aggregatePublisher = phonebookCollection .aggregate(Arrays.asList(groupStage, sortStage)) .collation(Collation.builder() .locale("de") .collationStrength(CollationStrength.PRIMARY) .build()); Flux.from(aggregatePublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
El código anterior genera los siguientes documentos:
{"_id": "Gunter", "nameCount": 2} {"_id": "Hannah", "nameCount": 1} {"_id": "Jürgen", "nameCount": 1} {"_id": "Klara", "nameCount": 1}
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API: