Visão geral
Neste guia, você pode aprender como usar agrupamentos com MongoDB para ordenar sua query ou resultados de operação de agregação por valores de string. Um agrupamento é um conjunto de regras de ordenação e correspondência de caracteres que se aplicam a um idioma e uma localidade específicos.
Você pode aprender mais sobre agrupamentos nas seguintes seções deste guia:
Importante
Biblioteca do Reator do Projeto
Este guia usa a biblioteca Project Reactor para consumir instâncias do Publisher retornadas pelos métodos de driver Java Reactive Streams. Para saber mais sobre a biblioteca do Projeto Reactor e como usá-la, consulte Introdução na documentação do Reactor. Para saber mais sobre como usamos os métodos da biblioteca do Project Reactor neste guia, consulte o guia Gravar dados no MongoDB.
Agrupamentos no MongoDB
O MongoDB classifica strings utilizando agrupamento binário por padrão. O agrupamento binário usa o padrão ASCII de valores de caracteres para comparar e ordenar strings. Determinados idiomas e localidades possuem convenções específicas de ordenação de caracteres que diferem dos valores de caracteres ASCII.
Por exemplo, no francês canadense, o caractere mais acentuado à direita (diacrítico) determina a ordem das strings quando todos os caracteres anteriores são iguais. Considere as seguintes palavras em francês canadense:
cote
coté
côte
côté
Ao usar o agrupamento binário, o MongoDB os classifica na seguinte ordem:
cote coté côte côté
Ao usar o agrupamento francês canadense, o MongoDB os classifica na seguinte ordem:
cote côte coté côté
Como especificar agrupamentos
MongoDB supports collations on most CRUD operations and aggregations. For a complete list of supported operations, see Operations that Support Collations in the MongoDB Server manual.
Você pode especificar o código de localidade e a variante opcional no seguinte formato de string:
"<locale code>@collation=<variant code>"
O exemplo a seguir especifica o código de locale "de" e o código de variante "phonebook":
"de@collation=phonebook"
Se você não especificar uma variante, use apenas o código de locale.
For a complete list of supported locales, see Supported Languages and Locales in the MongoDB Server manual.
As seções a seguir mostram maneiras diferentes de aplicar agrupamentos no MongoDB:
collection
You can only set a default collation to a collection during creation. However, you can specify a collation in a new index on an existing collection. All supported operations that scan the collection then apply the default collation. See the Index section of this guide for more information.
O exemplo a seguir mostra como especificar o agrupamento de localidade "en_US" ao criar uma nova coleção chamada items:
Mono.from(database.createCollection( "items", new CreateCollectionOptions().collation( Collation.builder().locale("en_US").build()))) .block();
Para verificar se você criou o agrupamento com sucesso, recupere uma lista dos índices nessa coleção da seguinte maneira:
List<Document> indexes = Flux.from(itemsCollection.listIndexes()) .collectList().block(); if (indexes != null) { indexes.forEach(idx -> System.out.println(idx.toJson())); }
A saída do código anterior deve conter o seguinte:
{ ... "collation": { "locale": "en_US", ... } ... }
Index
Você pode especificar um agrupamento ao criar um novo índice em uma coleção. O índice armazena documentos na ordem especificada, eliminando a necessidade de classificação na memória durante as query. Para usar o índice, a operação deve usar o mesmo agrupamento especificado no índice e ser coberta por esse índice.
O exemplo a seguir mostra como criar um índice no campo "nome" com o agrupamento de localidade "en_US" em ordem crescente:
IndexOptions idxOptions = new IndexOptions(); idxOptions.collation(Collation.builder().locale("en_US").build()); Mono.from(itemsCollection.createIndex( Indexes.ascending("name"), idxOptions)).block();
Para verificar se você criou o agrupamento com sucesso, recupere uma lista dos índices nessa coleção da seguinte maneira:
List<Document> indexes = Flux.from(itemsCollection.listIndexes()) .collectList().block(); if (indexes != null) { indexes.forEach(idx -> System.out.println(idx.toJson())); }
A saída do código anterior deve conter o seguinte:
{ ... "collation": { "locale": "en_US", ... } ... }
O exemplo a seguir mostra uma operação que especifica o mesmo agrupamento e é coberta pelo índice criado no exemplo 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();
(operação)
You can override the default collation by passing a new collation to a supported operation. However, without an index, your query performs in-memory sorting, which is slower than using an indexed collation. For more information about the disadvantages of sorting operations not covered by an index, see Use Indexes to Sort Query Results in the MongoDB Server manual.
O exemplo a seguir mostra uma operação de query com as seguintes características:
The referenced collection has a default
"en_US"collation index, similar to the one specified in the Collection section.A query especifica o agrupamento islandês (
"is"). Como isso difere do agrupamento de índice, a query não usa o índice e, em vez disso, executa uma classificação na memória.
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 não suportam agrupamentos
A maioria dos tipos de índice do MongoDB oferece suporte a agrupamentos. No entanto, os seguintes tipos oferecem suporte apenas à comparação binária e não oferecem suporte a agrupamentos:
Opções de agrupamento
Esta seção aborda várias opções de agrupamento e como especificá-las para refinar ainda mais o comportamento de ordenação e correspondência.
Opção de agrupamento | Descrição |
|---|---|
localidade | Required. The ICU locale code for language and variant. |
de trás para frente | Specifies whether to consider diacritics from the end of the string first. |
Sensibilidade a maiúsculas e minúsculas | Specifies whether to consider case (upper or lower) as different values. |
alternar | Specifies whether to consider spaces and punctuation. |
caseFirst | Specifies whether to consider uppercase or lowercase first. |
Variável máxima | Specifies whether to ignore whitespace or both whitespace and punctuation. This setting is only valid when the alternate setting is "shifted". |
força | Specifies the ICU comparison level. The default value is "tertiary". For more information about each level, see the ICU Comparison Levels. |
normalização | Specifies whether to perform unicode normalization on the text as needed. For more information about unicode normalization, see Unicode Normalization Forms. |
numericOrdering | Specifies whether to order numbers according to numeric value rather than collation order. |
Você pode usar a classe Collation.Builder para especificar valores para as opções de agrupamentos anteriores. Chame o método build() para construir um objeto Collation conforme mostrado no exemplo a seguir:
Collation.builder() .caseLevel(true) .collationAlternate(CollationAlternate.SHIFTED) .collationCaseFirst(CollationCaseFirst.UPPER) .collationMaxVariable(CollationMaxVariable.SPACE) .collationStrength(CollationStrength.SECONDARY) .locale("en_US") .normalization(false) .numericOrdering(true) .build();
For more information about the corresponding methods and parameters, see the API documentation for Collation.Builder.
Exemplos de agrupamento
Esta seção contém exemplos de como usar operações do MongoDB que suportam agrupamentos. Para cada exemplo, suponha que você comece com a seguinte coleção 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" }
Os exemplos a seguir usam o locale "de@collation=phonebook" e os agrupamentos de variantes. A parte "de" do agrupamento especifica a locale alemã e a parte "collation=phonebook" especifica uma variante. O agrupamento de locale "de" contém regras para priorizar nomes próprios, identificados pela capitalização da primeira letra. Na variante "collation=phonebook", os caracteres com umlauts são ordenados antes dos mesmos caracteres sem eles em uma classificação crescente.
Exemplo de find() e sort()
O exemplo a seguir mostra como aplicar um agrupamento ao recuperar resultados classificados de uma coleção. Para executar esta operação, chame find() na coleção de exemplo e encadeie os métodos collation() e sort() para especificar a ordem na qual você deseja receber os 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();
Quando você executa esta operação na coleção de exemplo, a saída se assemelha ao seguinte:
{"_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 obter mais informações sobre os métodos e as classes mencionadas nesta seção, consulte a seguinte documentação da API:
Exemplo de findOneAndUpdate ()
O exemplo a seguir especifica um agrupamento em uma operação findOneAndUpdate() instanciando um objeto FindOneAndUpdateOptions e passando-o como um parâmetro. O exemplo executa as seguintes operações:
Retrieves the first document in the example collection that precedes "Gunter" in ascending order.
Define as opções para a operação, incluindo o agrupamento
"de@collation=phonebook".Adiciona um novo campo "verified" com o valor "true".
Recupera e imprime o documento atualizado.
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()); }
Como "Günter" vem lexicalmente antes de "Gunter" usando o agrupamento de@collation=phonebook em ordem crescente, a operação anterior retorna o seguinte documento:
Updated document: {"_id": 3, "first_name": "Günter", "verified": true}
Para obter mais informações sobre os métodos e as classes mencionadas nesta seção, consulte a seguinte documentação da API:
Exemplo de findOneAndDelete()
O exemplo a seguir especifica um agrupamento de ordenação numérica em uma operação findOneAndDelete() instanciando um objeto FindOneAndDeleteOptions e passando-o como parâmetro. A coleção contém os seguintes documentos:
{ "_id" : 1, "a" : "16 apples" } { "_id" : 2, "a" : "84 oranges" } { "_id" : 3, "a" : "179 bananas" }
O agrupamento define a opção locale como "en" e a opção numericOrdering como "true" para classificar as strings com base em seu 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()); }
Depois de executar a operação anterior, seu resultado será semelhante ao seguinte:
Deleted document: {"_id": 3, "a": "179 bananas"}
O valor numérico da string "179" é maior que 100, portanto, o documento anterior é a única correspondência. Sem ordem numérica, a agrupamentos binária classifica "100" antes de "16", "84" e "179", portanto, o filtro corresponde a todos os documentos.
Para obter mais informações sobre os métodos e as classes mencionadas nesta seção, consulte a seguinte documentação da API:
Exemplo de agregação
O exemplo a seguir mostra como especificar um agrupamento em uma operação de agregação. Para executar uma agregação, chame o método aggregate() em um objeto MongoCollection.
Para especificar um agrupamento para uma operação de agregação, chame o método collation() no AggregatePublisher retornado pela operação de agregação. Especifique um estágio de agregação de classificação em seu pipeline para aplicar o agrupamento.
The following example constructs an aggregation pipeline on the example collection and applies a collation by specifying the following:
Um estágio de agregação de grupo usando
Aggregates.group()para identificar cada documento pelo campofirst_namee usar esse valor como_iddo resultado.Um acumulador no estágio de grupo para somar o número de instâncias de valores correspondentes no campo
first_name.Uma classificação ascendente no campo
_iddos documentos de saída.Um objeto de agrupamento especificando a locale alemã e uma força de agrupamento que ignora acentos e umlauts.
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();
O código anterior gera os seguintes documentos:
{"_id": "Gunter", "nameCount": 2} {"_id": "Hannah", "nameCount": 1} {"_id": "Jürgen", "nameCount": 1} {"_id": "Klara", "nameCount": 1}
Para obter mais informações sobre os métodos e as classes mencionadas nesta seção, consulte a seguinte documentação da API: