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 saber 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
O MongoDB oferece suporte a agrupamentos na maioria das operações CRUD e agregações. Para obter uma lista completa das operações suportadas, consulte Operações que suportam agrupamentos no manual do MongoDB Server .
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 da locale .
Para obter uma lista completa dos locais suportados,consulte Idiomas e locais suportados no manual do MongoDB Server .
As seções a seguir mostram maneiras diferentes de aplicar agrupamentos no MongoDB:
collection
Você só pode definir um agrupamento padrão para uma coleção durante a criação. No entanto, você pode especificar um agrupamento em um novo índice em uma coleta existente. Todas as operações suportadas que verificam a coleção aplicam o agrupamento padrão. Consulte a seção Índice deste guia para obter mais informações.
O exemplo a seguir mostra como especificar o agrupamento de locale "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 queries. 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 locale "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)
Você pode substituir o agrupamento padrão passando um novo agrupamento para uma operação aceita. No entanto, sem um índice, sua query executa a classificação na memória, que é mais lenta do que usar um agrupamento indexado. Para obter mais informações sobre as desvantagens das operações de classificação não cobertas por um índice, consulte Usar índices para classificar resultados de queries no manual do MongoDB Server .
O exemplo abaixo mostra uma operação de query com as seguintes características:
A consulta especifica o agrupamento Islandês (
"is"). Como isso é diferente do agrupamento do índice, a consulta não usa o índice e 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 MongoDB suporta agrupamento. No entanto, os tipos a seguir suportam apenas comparação binária e não suportam agrupamento:
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 | Obrigatório. O código de locale da ICU para idioma e variante. |
de trás para frente | Especifica se os diacríticos do final da string devem ser considerados primeiro. |
Sensibilidade a maiúsculas e minúsculas | Especifica se deve considerar maiúsculas e minúsculas (superiores ou inferiores) como valores diferentes. |
alternar | Especifica se espaços e pontuação devem ser considerados. |
caseFirst | Especifica se deve considerar primeiro letras maiúsculas ou minúsculas. |
Variável máxima | Especifica se os espaços em branco devem ser ignorados ou ambos os espaços em branco e pontuação. Esta configuração só é válida quando a configuração alternativa é "deslocada". |
força | Especifica o nível de comparação da UTI. O valor padrão é "terciário". Para obter mais informações sobre cada nível, consulte os Níveis de comparação da ICU. |
normalização | Especifica se a normalização unicode deve ser executada no texto conforme necessário. Para obter mais informações sobre normalização unicode, consulte Formulários de normalização unicode. |
numericOrdering | Especifica se os números devem ser ordenados de acordo com o valor numérico em vez da ordem de agrupamento. |
Você pode usar a classe Collation.Builder para especificar valores para as opções de agrupamento anteriores. Chame o método build() para construir um objeto Collation como mostrado no seguinte exemplo:
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 obter mais informações sobre os métodos e parâmetros correspondentes, consulte a documentação da API para Collation.Builder.
Exemplos de agrupamento
Esta seção contém exemplos de como usar as operações do MongoDB que oferecem suporte a 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 agrupamento de locale e variante do "de@collation=phonebook". A parte "de" do agrupamento especifica a locale alemão 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 collection. Para executar esta operação, chame find() na coleção de exemplo e encadeie os métodos collation() e sort() para especificar a ordem em que 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:
Recupera o primeiro documento na coleção de exemplo que precede "Gunter" em ordem crescente.
Define 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" é 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 ordem numérica em uma operação findOneAndDelete() instanciando um objeto FindOneAndDeleteOptions e passando-o como um 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, então o documento anterior é a única correspondência. Sem ordenação numérica, o agrupamento binário classifica "100" antes de "16", "84" e "179", para que o filtro corresponda 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 em seu pipeline para aplicar o agrupamento.
O exemplo a seguir constrói um pipeline de agregação na coleção de exemplo e aplica um agrupamento especificando o seguinte:
Um estágio de agregação de grupo utilizando
Aggregates.group()para identificar cada documento pelo campofirst_namee utilizar este valor como o_iddo resultado.Um acumulador no estágio de grupos 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 que especifica a locale alemã e a força de um 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: