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 aprender más sobre 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 intercalación en la mayoría de las operaciones CRUD y agregaciones. Para obtener una lista completa de las operaciones admitidas, consulte Operaciones que admiten intercalación en el manual de MongoDB Server.
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 localización "de" y el código de variante "phonebook":
"de@collation=phonebook"
Si no especifica una variante, utilice solo el código de localización.
Para obtener una lista completa de las localizaciones admitidas, consulte Lenguajes y localizaciones admitidos en el manual de MongoDB Server.
Las siguientes secciones muestran diferentes formas de aplicar intercalaciones en MongoDB:
Colección
Solo puede establecer una intercalación por defecto en una colección durante la creación. Sin embargo, puede especificar una intercalación en un nuevo índice en una colección existente. Todas las operaciones admitidas que escanean la colección aplican la intercalación por defecto. 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 localización "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
Puede especificar una intercalación al crear un nuevo índice en una colección. El índice almacena documentos en el orden especificado, lo que elimina la necesidad de ordenación en memoria durante las query. Para usar el índice, la operación debe usar la misma intercalación que la especificada en el índice y estar cubierta por ese índice.
El siguiente ejemplo muestra cómo crear un índice en el campo "nombre" con la intercalación de localización "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
Puede anular la intercalación por defecto pasando una nueva intercalación a una operación compatible. Sin embargo, sin un índice, su query realiza una clasificación en memoria, que es más lenta que utilizar una intercalación indexada. Para obtener más información sobre las desventajas de las operaciones de clasificación no cubiertas por un índice, consulte Utilizar índices para clasificar los resultados de las queries en el manual de MongoDB Server.
El siguiente ejemplo muestra una operación de query con las siguientes características:
La colección referenciada tiene un índice de intercalación
"en_US"por defecto, similar al especificado en la sección Colección.La query especifica la intercalación islandesa (
"is"). Debido a que esto difiere de la intercalación del índice, la query no utiliza el índice y, en su lugar, realiza una clasificació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 índice de MongoDB admiten la intercalación. Sin embargo, los siguientes tipos solo admiten la comparación binaria y no admiten la 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 | Requerido. El código de localización de ICU para el lenguaje y la variante. |
Hacia atrás | Especifica si se deben considerar los diacríticos desde el final del string primero. |
Sensibilidad a mayúsculas y minúsculas | Especifica si se debe considerar el caso (mayúsculas o 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 debe considerar primero mayúsculas o 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 "desplazada". |
Fuerza | Especifica el nivel de comparación de ICU. El valor por defecto es "terciario". Para obtener más información sobre cada nivel, consulte los Niveles de comparación de ICU. |
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 Formas de normalización Unicode. |
Ordenación numérica | Especifica si se deben ordenar los números según el valor numérico en lugar del 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 correspondientes y los parámetros que requieren, consulte la Documentación de la API para intercalación.Builder.
Ejemplos de intercalación
Esta sección contiene ejemplos de cómo utilizar 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 localización "de@collation=phonebook" y la intercalación de variantes. La parte "de" de la intercalación especifica la localización alemana y la parte "collation=phonebook" especifica una variante. La intercalación de localizació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 mismos caracteres sin ellos en una ordenación 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, llama a find() en la colección de ejemplos y encadena los métodos collation() y sort() para especificar el orden en el que deseas 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 ejemplo que precede a "Gunter" en orden ascendente.
Configura opciones para la operación, incluyendo la intercalación
"de@collation=phonebook".Añade 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" aparece léxicamente antes de "Gunter" al utilizar la intercalación de@collation=phonebook en orden ascendente, la operación anterior 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 ordenación numérica en una operación findOneAndDelete() al instanciar un objeto FindOneAndDeleteOptions y pasarlo 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 "true" para ordenar las cadenas en función de 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 string "179" es mayor que 100, por lo que el documento anterior es el único que coincide. Sin ordenación numérica, 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 ordenamiento en su pipeline para aplicar la intercalación.
El siguiente ejemplo construye un pipeline 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 localización alemana y una fuerza 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: