Visão geral
Neste guia, você pode aprender como usar a Extensão MongoDB para Hibernar ORM para especificar uma consulta de banco de dados .
Você pode refinar o conjunto de documentos que uma query retorna criando um filtro de queries. Um filtro de queries é uma expressão que especifica os critérios de pesquisa que o MongoDB usa para corresponder a documentos em uma operação de leitura ou gravação. Para criar filtros de queries do MongoDB, use declarações Hibernate linguagem de query (HQL) ou Jakarta Persistence linguagem de query (JPQL).
Dica
Para saber mais sobre a sintaxe HQL e JPQL, consulte Um Guia da linguagem de query do Hibernate na documentação do ORM do Hibernate.
Observação
Suporte a consultas
A extensão MongoDB para hibernação ORM não oferece suporte a todas as funcionalidades de query do MongoDB e hibernação. Para saber mais, consulte Suporte a query na página Compatibilidade de recursos.
Dados de amostra
Os exemplos neste guia usam a entidade Movie, que representa a coleção sample_mflix.movies dos conjuntos de dados de amostra do Atlas. A entidade Movie tem a seguinte definição:
import com.mongodb.hibernate.annotations.ObjectIdGenerator;import org.bson.types.ObjectId;import java.time.Instant;import java.util.List;import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;import jakarta.persistence.FetchType;import jakarta.persistence.Id;import jakarta.persistence.OneToMany;import jakarta.persistence.Table;
@Entity@Table(name = "movies")public class Movie { @Id @ObjectIdGenerator private ObjectId id; private String title; private String plot; private int year; private List<String> cast; private List<String> directors; private Instant released; @Embedded private Awards awards; @OneToMany(mappedBy = "movie", fetch = FetchType.LAZY) private List<Comment> comments;
public Movie(String title, String plot, int year, List<String> cast, List<String> directors, Instant released, Awards awards) { this.title = title; this.plot = plot; this.year = year; this.cast = cast; this.directors = directors; this.released = released; this.awards = awards; }
public Movie() {
}
public ObjectId getId() { return id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getPlot() { return plot; }
public void setPlot(String plot) { this.plot = plot; }
public int getYear() { return year; }
public void setYear(int year) { this.year = year; }
public List<String> getCast() { return cast; }
public void setCast(List<String> cast) { this.cast = cast; }
public List<String> getDirectors() { return directors; }
public void setDirectors(List<String> directors) { this.directors = directors; }
public Awards getAwards() { return awards; }
public void setAwards(Awards awards) { this.awards = awards; }
public Instant getReleased() { return released; }
public void setReleased(Instant released) { this.released = released; }
public List<Comment> getComments() { return comments; }
public void setComments(List<Comment> comments) { this.comments = comments; }}Para aprender como criar um aplicativo Java que use a Extensão MongoDB para Hibernate ORM para interagir com essa coleção de amostras do MongoDB, veja o tutorial Get Started.
Os exemplos de código nesta página também usam o seguinte Awards @Struct agregado incorporável:
@Embeddable@Struct(name = "Awards")public class Awards { private int wins; private int nominations; private String text;
public Awards(int wins, int nominations, String text) { this.wins = wins; this.nominations = nominations; this.text = text; }
public Awards() {
}
public int getWins() { return wins; }
public void setWins(int wins) { this.wins = wins; }
public int getNominations() { return nominations; }
public void setNominations(int nominations) { this.nominations = nominations; }
public String getText() { return text; }
public void setText(String text) { this.text = text; }}Importante
Contextos de persistência
Para habilitar o ORM do Hibernate para interagir com o banco de dados, você deve executar operações dentro de um contexto de persistência utilizando um Hibernate Session ou um Jakarta Persistence EntityManager. Use o HQL para definir queries de sessão e use o JPQL para definir queries do gerente de entidades.
Antes de executar os exemplos neste guia, adicione o contexto de persistência e o código de gerenciamento de transações ao seu aplicativo que se assemelha ao código a seguir:
var sf = HibernateUtil.getSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();
// ... Perform CRUD operations here
tx.commit();session.close();sf.close();Para utilizar uma sessão, você deve criar um arquivo HibernateUtil.java que configure um SessionFactory. Para saber mais, veja a etapa Configurar seu aplicativo do tutorial de Introdução.
// Replace <persistence unit> with the name of your persistence unit in the persistence.xml file EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence unit>"); EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin();
// ... Perform CRUD operations here
entityManager.getTransaction().commit();entityManager.close();emf.close;Para utilizar um EntityManager, você deve criar um arquivo persistence.xml que declara uma unidade de persistência. Para aprender mais, veja o Tutorial usando APIs padrão JPA na documentação do ORM do Hibernate.
Propriedade de configuração de semântica nula obrigatória
Antes de criar uma instância SessionFactory, você deve definir a propriedade de configuração com.mongodb.hibernate.semantics.nulls como MQL. Esta propriedade é obrigatória, não tem valor padrão e atualmente não aceita nenhum outro valor. Se você omitir a propriedade ou defini-la com outro valor, a extensão Hibernate ORM lançará uma HibernateException.
Quando você define com.mongodb.hibernate.semantics.nulls como MQL, a propriedade declara que o comportamento relacionado a null segue a MongoDB linguagem de query (MQL) que a extensão Hibernate ORM produz durante a tradução, não a lógica de três valores definida pela semântica null do SQL.
Como a extensão Hibernate ORM não oferece garantias de uma tradução específica, os resultados do comportamento relacionado a nulos podem mudar entre as versões.
O exemplo a seguir define a propriedade com.mongodb.hibernate.semantics.nulls no seu arquivo hibernate.properties:
com.mongodb.hibernate.semantics.nulls=MQLUse operadores de comparação
Você pode usar os seguintes operadores em suas declarações de query para comparar valores de campo com valores de query especificados:
=: Correspondência de igualdade<>: Correspondência de desigualdade>: maior que as comparações>=: Comparações maiores ou iguais<: menos do que comparações<=: Comparações menores ou iguais
O exemplo a seguir recupera documentos que têm um valor de year maior ou igual a 2015 da coleção sample_mflix.movies:
var comparisonResult = session.createQuery("from Movie where year >= :y", Movie.class) .setParameter("y", 2015) .getResultList();for (var m : comparisonResult) { System.out.println("Title: " + m.getTitle());}var comparisonResult = entityManager.createQuery("select m from Movie m where m.year >= :y", Movie.class) .setParameter("y", 2015) .getResultList();for (var m : comparisonResult) { System.out.println("Title: " + m.getTitle());}Compare Vários Campos de uma Só Vez
Um predicado de valor de linha compara uma lista de campos entre parênteses com uma lista de valores entre parênteses em uma única expressão. A extensão Hibernate ORM oferece suporte a predicados de valor de linha que usam os seguintes operadores:
=: Correspondência de igualdade<>: Correspondência de desigualdadeINeNOT IN: Correspondência com uma lista de linhas de valores
Você pode fornecer os valores como parâmetros vinculados ou como literais, e cada lista deve conter o mesmo número de componentes.
O exemplo a seguir recupera documentos que têm um valor "Jurassic World" para title e um valor 2015 para year da coleção sample_mflix.movies:
var rowValueResult = session.createQuery("from Movie where (title, year) = (:t, :y)", Movie.class) .setParameter("t", "Jurassic World") .setParameter("y", 2015) .getResultList();for (var m : rowValueResult) { System.out.println("Title: " + m.getTitle());}var rowValueResult = entityManager.createQuery("select m from Movie m where (m.title, m.year) = (:t, :y)", Movie.class) .setParameter("t", "Jurassic World") .setParameter("y", 2015) .getResultList();for (var m : rowValueResult) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM compara cada par de componentes separadamente. O predicado de valor de linha anterior é traduzido para o seguinte estágio $match:
{ "$match": { "$and": [ { "title": { "$eq": "Jurassic World" } }, { "year": { "$eq": 2015 } } ] }}Um predicado de valor de linha que usa o operador <> é traduzido para a mesma expressão $and envolvida em uma expressão $nor.
Se você comparar os campos com outra lista de campos, como em where (title1, year1) = (title2, year2), a extensão Hibernate ORM traduz o predicado para uma expressão $expr.
Você pode usar um predicado de valor de linha em uma cláusula SELECT. O predicado é avaliado como um valor booleano na projeção.
Observação
Semântica de Nulo
Os predicados de valor de linha seguem a semântica nula da linguagem de query do MongoDB em vez da lógica ternária do Hibernate ORM, portanto, um predicado <> corresponde a documentos nos quais um componente é nulo ou está ausente. Para aprender mais, consulte a seção Compare valores de campo a nulo deste guia.
Corresponder a uma lista de linhas de valor
Para corresponder a uma linha de campos com várias linhas de valores, use o operador IN. O exemplo seguinte recupera documentos que correspondem a um de dois pares de title e year:
var rowValueInResult = session.createQuery( "from Movie where (title, year) in (('Jurassic World', 2015), ('Ex Machina', 2015))", Movie.class) .getResultList();for (var m : rowValueInResult) { System.out.println("Title: " + m.getTitle());}var rowValueInResult = entityManager.createQuery( "select m from Movie m where (m.title, m.year) in (('Jurassic World', 2015), ('Ex Machina', 2015))", Movie.class) .getResultList();for (var m : rowValueInResult) { System.out.println("Title: " + m.getTitle());}O predicado de valor de linha anterior é traduzido para o seguinte estágio $match:
{ "$match": { "$or": [ { "$and": [ { "title": { "$eq": "Jurassic World" } }, { "year": { "$eq": 2015 } } ] }, { "$and": [ { "title": { "$eq": "Ex Machina" } }, { "year": { "$eq": 2015 } } ] } ] }}Se a lista contiver apenas uma linha de valores, o predicado será traduzido apenas para a expressão $and. Um predicado NOT IN é traduzido para a expressão $or envolvida em uma expressão $nor.
Importante
Comparações de ordenação
A extensão Hibernate ORM não oferece suporte a predicados de valor de linha que usam o operador >, >=, < ou <=. Esses predicados fazem com que a extensão Hibernate ORM gere um FeatureNotSupportedException.
Comparar valores de campo com nulo
Ao comparar um campo com null usando um operador de comparação, a extensão Hibernate ORM aplica a semântica nula da MongoDB linguagem de query em vez da lógica ternária que o Hibernate ORM define.
Observação
Lógica ternária do Hibernate para null
O Hibernate ORM v6.3 e posterior avalia uma comparação com null como null, que um predicado trata como false. A extensão Hibernate ORM não implementa esse comportamento. Para aprender mais sobre quais recursos a extensão Hibernate ORM suporta, consulte Suporte a tipo de dados na página Compatibilidade de recursos.
Os operadores de comparação do MongoDB avaliam tanto um campo ausente quanto um campo que armazena um valor explícito de null como null. Como resultado, uma comparação = null corresponde a documentos em que o campo armazena null e documentos em que o campo está ausente. Uma comparação <> null ou != null corresponde a documentos em que o campo armazena qualquer outro valor.
O exemplo a seguir usa o operador = para recuperar documentos que têm um valor null ou ausente cast da coleção sample_mflix.movies:
var nullComparisonResult = session.createQuery("from Movie where cast = null", Movie.class) .getResultList();for (var m : nullComparisonResult) { System.out.println("Title: " + m.getTitle());}var nullComparisonResult = entityManager.createQuery("select m from Movie m where m.cast = null", Movie.class) .getResultList();for (var m : nullComparisonResult) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz esta query para o seguinte estágio $match:
{ "$match": { "cast": { "$eq": null } }}As comparações que usam os operadores >, >=, < e <= seguem a ordem de comparação BSON do MongoDB para campos inexistentes. Como null é seu próprio tipo BSON, uma comparação >= null ou <= null corresponde a documentos nos quais o campo armazena null ou está ausente. Uma comparação > null ou < null não corresponde a nenhum documento.
Para corresponder a null e valores ausentes usando um predicado em vez de um operador de comparação, consulte as seções IS NULL e IS NOT NULL deste guia.
Usar expressões computadas
Você pode calcular um valor a partir de valores de campo, literais e parâmetros de query. Você pode então retornar esse valor em uma cláusula SELECT ou compará-lo em uma cláusula WHERE. A extensão Hibernate ORM traduz uma expressão calculada para uma expressão de agregação do MongoDB.
A extensão Hibernate ORM suporta os seguintes operadores aritméticos em expressões computadas:
+: Adição, que traduz para$add-: Subtração, que se traduz em$subtract*: Multiplicação, que se traduz em$multiply/: Divisão, que se traduz em$divide-e+unários
Observação
A divisão sempre retorna um número inteiro
O Hibernate ORM traduz a divisão em um pipeline de agregação do MongoDB para o operador $divide do MongoDB, que sempre retorna um double. A extensão Hibernate ORM trunca o resultado envolvendo $divide em $toInt, ou $toLong se o tipo de resultado for BIGINT. Esse comportamento se aplica ao operador / e ao método quot() da API Criteria, independentemente de você habilitar a configuração PORTABLE_INTEGER_DIVISION do Hibernate ORM.
O operador div não é suportado.
Você também pode usar os operador de comparação descritos na seção Usar Operador de Comparação em expressões computadas.
Importante
Limitações de Operandos
Um operando de uma expressão computada deve ser uma referência de campo, um literal ou um parâmetro de query. A extensão Hibernate ORM não oferece suporte a chamar de função como operandos.
Como o Hibernate ORM reescreve o operador % do HQL para chamar uma função mod(), % também não é suportado. Para realizar uma operação módulo, use o método CriteriaBuilder.mod() da Criteria API, que é traduzido para o operador $mod do MongoDB.
O método CriteriaBuilder.quot() da API Criteria se comporta de forma idêntica ao operador /.
Realizar cálculos aritméticos em uma projeção
Ao selecionar uma expressão computada, a extensão Hibernate ORM adiciona o valor computado ao estágio $project. Se você atribuir um alias à expressão usando a palavra-chave AS, a extensão Hibernate ORM usará o alias como a chave de projeção. Caso contrário, ele gera uma chave no formato #c_<n>.
O exemplo a seguir calcula a idade de cada filme "Hairspray" na coleção sample_mflix.movies subtraindo o valor do campo year de um parâmetro de query:
var arithmeticResult = session.createQuery( "select title, :currentYear - year as age from Movie where title = :title", Object[].class) .setParameter("currentYear", 2026) .setParameter("title", "Hairspray") .getResultList();for (var row : arithmeticResult) { System.out.println("Title: " + row[0] + ", Age: " + row[1]);}var arithmeticResult = entityManager.createQuery( "select m.title, :currentYear - m.year as age from Movie m where m.title = :title", Object[].class) .setParameter("currentYear", 2026) .setParameter("title", "Hairspray") .getResultList();for (var row : arithmeticResult) { System.out.println("Title: " + row[0] + ", Age: " + row[1]);}A extensão Hibernate ORM traduz a expressão computada anterior para o seguinte estágio $project:
{ "$project": { "title": true, "age": { "$subtract": [ 2026, "$year" ] }, "_id": 0 }}Filtro em uma expressão computada
Na cláusula WHERE, você pode comparar uma expressão calculada com um valor ou comparar dois valores de campo entre si. Quando qualquer um dos lados de uma comparação não é uma referência de campo direta ou um valor, a extensão Hibernate ORM envolve a comparação no operador $expr do MongoDB. As comparações entre um campo e um valor continuam a usar a forma compacta { field: { operator: value } }.
O exemplo a seguir recupera "Hairspray" filmes lançados menos de 20 anos antes de 2026:
var computedFilterResult = session.createQuery( "from Movie where title = :title and :currentYear - year < 20", Movie.class) .setParameter("title", "Hairspray") .setParameter("currentYear", 2026) .getResultList();for (var m : computedFilterResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}var computedFilterResult = entityManager.createQuery( "select m from Movie m where m.title = :title and :currentYear - m.year < 20", Movie.class) .setParameter("title", "Hairspray") .setParameter("currentYear", 2026) .getResultList();for (var m : computedFilterResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}A extensão Hibernate ORM traduz a query anterior para o seguinte estágio $match, no qual a comparação title usa a forma compacta e a comparação calculada usa $expr:
{ "$match": { "$and": [ { "title": { "$eq": "Hairspray" } }, { "$expr": { "$lt": [ { "$subtract": [ 2026, "$year" ] }, 20 ] } } ] }}Projeto um resultado de comparação
Você pode usar uma comparação em uma declaração SELECT para retornar seu resultado booleano em vez de usar a comparação como um filtro.
O exemplo a seguir retorna o título de cada filme "Hairspray" e se o filme foi lançado após 2000:
var comparisonResult = session.createQuery( "select title, year > 2000 as isRecent from Movie where title = :title", Object[].class) .setParameter("title", "Hairspray") .getResultList();for (var row : comparisonResult) { System.out.println("Title: " + row[0] + ", Recent: " + row[1]);}var comparisonResult = entityManager.createQuery( "select m.title, m.year > 2000 as isRecent from Movie m where m.title = :title", Object[].class) .setParameter("title", "Hairspray") .getResultList();for (var row : comparisonResult) { System.out.println("Title: " + row[0] + ", Recent: " + row[1]);}A extensão Hibernate ORM traduz a comparação anterior para o seguinte estágio $project:
{ "$project": { "title": true, "isRecent": { "$gt": [ "$year", 2000 ] }, "_id": 0 }}Expressões de caso de uso para lógica condicional
Uma expressão CASE retorna um valor diferente para cada condição que você especificar. A extensão Hibernate ORM oferece suporte a expressões CASE simples e pesquisadas de HQL e JPQL:
Caso simples: A expressão após a palavra-chave
CASEé comparada quanto à igualdade com o valor em cada cláusulaWHEN. Um exemplo de uma expressão de caso simples écase year when 2000 then 'Modern' else 'Classic' end.Caso pesquisado: Cada cláusula
WHENespecifica um predicado. Um exemplo de uma expressão de caso pesquisado écase when year > 2000 then 'Modern' else 'Classic' end.
A extensão Hibernate ORM traduz uma expressão CASE para o operador MongoDB $switch, que cria uma ramificação para cada cláusula WHEN e avalia as ramificações na ordem que você especificar. A cláusula ELSE torna-se o valor default de $switch. Se você omitir a cláusula ELSE, a expressão retornará null quando nenhuma ramificação corresponder.
Uma expressão CASE pode retornar uma expressão computada, e você pode usar uma expressão CASE nas seguintes posições:
Uma cláusula
SELECT, como mostrado no exemplo a seguir.Um operando de uma comparação em uma cláusula
WHERE, que a extensão Hibernate ORM envolve no operador$exprdo MongoDB.A cláusula
SETde uma declaração de atualizar em massa. Para ver um exemplo, consulte a seção Exemplo de atualização múltipla com base em lógica condicional no guia Executar operações CRUD.
O exemplo a seguir retorna o título de cada filme "Hairspray" e um rótulo que depende do valor year do filme:
var caseResult = session.createQuery( "select title, case when year > 2000 then 'Modern' else 'Classic' end as era " + "from Movie where title = :title", Object[].class) .setParameter("title", "Hairspray") .getResultList();for (var row : caseResult) { System.out.println("Title: " + row[0] + ", Era: " + row[1]);}var caseResult = entityManager.createQuery( "select m.title, case when m.year > 2000 then 'Modern' else 'Classic' end as era " + "from Movie m where m.title = :title", Object[].class) .setParameter("title", "Hairspray") .getResultList();for (var row : caseResult) { System.out.println("Title: " + row[0] + ", Era: " + row[1]);}A extensão Hibernate ORM traduz a expressão CASE anterior para o seguinte estágio $project:
{ "$project": { "title": true, "era": { "$switch": { "branches": [ { "case": { "$gt": [ "$year", 2000 ] }, "then": "Modern" } ], "default": "Classic" } }, "_id": 0 }}Importante
Limitações da expressão CASE
Como uma expressão CASE produz uma expressão de agregação do MongoDB, você não pode usá-la em uma posição que exija uma referência de campo ou um valor literal. A extensão Hibernate ORM gera um FeatureNotSupportedException se você usar uma expressão CASE:
em uma cláusula
ORDER BY, a menos que a mesma expressãoCASEseja uma chaveGROUP BY.como a expressão de correspondência de um predicado
LIKE.como a expressão de teste de um predicado
INouIS NULL.como um predicado de cláusula
WHEREem vez de um operando de um.
Use operadores de predicado
A extensão Hibernate ORM suporta os seguintes operadores de comparação de predicados em suas declarações de query:
Observação
A extensão Hibernate ORM não oferece suporte a todos os operador de comparação. Para aprender mais sobre as limitações de suporte, consulte Suporte a Query na página Compatibilidade de recursos.
Existe
O predicado EXISTS corresponde a documentos que possuem um campo específico e retorna apenas um resultado para cada documento pai correspondente, independentemente de quantos elementos do array correspondam.
Observação
Limitações da subconsulta EXISTS
A extensão Hibernate ORM suporta subconsultas EXISTS apenas sobre um campo array da entidade pai, e apenas na cláusula WHERE. A extensão Hibernate ORM não suporta subconsultas EXISTS que:
Query sobre uma entidade sem especificar primeiro um campo
Compare campos no mesmo documento pai
Aparecer na cláusula
SELECT
Para um exemplo completo, consulte a seção Query em elementos de um array incorporado deste guia.
entre
O predicado BETWEEN corresponde a documentos que têm um valor de campo dentro de uma faixa especificada.
O exemplo a seguir usa o predicado BETWEEN para recuperar documentos que têm um valor year entre 2012 e 2013, inclusive, da coleção sample_mflix.movies:
var betweenResult = session.createQuery("from Movie where year between :start and :end", Movie.class) .setParameter("start", 2012) .setParameter("end", 2013) .getResultList();for (var m : betweenResult) { System.out.println("Title: " + m.getTitle());}var betweenResult = entityManager.createQuery("select m from Movie m where m.year between :start and :end", Movie.class) .setParameter("start", 2012) .setParameter("end", 2013) .getResultList();for (var m : betweenResult) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado BETWEEN anterior para o seguinte estágio $match:
{ "$match": { "year": { "$gte": 2012, "$lte": 2013 } }}Em
O predicado IN corresponde a documentos em que o valor de um campo é igual a qualquer valor em uma lista especificada. Você pode fornecer os valores da lista como literais, parâmetros nomeados ou parâmetros posicionais.
O exemplo a seguir usa o predicado IN para recuperar documentos que têm um valor year de 1994 ou 1996 da coleção sample_mflix.movies:
var inResult = session.createQuery("from Movie where year in (:first, :second)", Movie.class) .setParameter("first", 1994) .setParameter("second", 1996) .getResultList();for (var m : inResult) { System.out.println("Title: " + m.getTitle());}var inResult = entityManager.createQuery("select m from Movie m where m.year in (:first, :second)", Movie.class) .setParameter("first", 1994) .setParameter("second", 1996) .getResultList();for (var m : inResult) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado IN anterior para o seguinte estágio $match:
{ "$match": { "year": { "$in": [ 1994, 1996 ] } }}Uma lista vazia é válida, mas nunca corresponde a nenhum documento. Por exemplo, year in () não corresponde a nenhum documento.
Observação
Limitações do predicado IN
A extensão Hibernate ORM suporta o predicado IN apenas quando o valor à esquerda de IN é um caminho do campo. A extensão Hibernate ORM não suporta predicados IN que:
Use uma subquery como a lista de valores.
Teste um valor em relação a uma expressão com valor de array, como em
:value in m.cast. Para comparar um valor com um campo de array, use a funçãoarray_contains().
Para aprender mais sobre como fazer uma query em um array, consulte a seção Query an Array campo deste guia.
não em
O predicado NOT IN corresponde a documentos nos quais um valor de campo não é igual a nenhum valor em uma lista especificada. NOT IN aceita as mesmas formas de lista e tem as mesmas limitações que o predicado IN.
O exemplo a seguir usa o predicado NOT IN para recuperar documento que tenham um valor title diferente de "Romeo and Juliet" ou "Best in Show" da coleção sample_mflix.movies. Como NOT IN exclui apenas os valores listados, o exemplo chama o método setMaxResults() para limitar o conjunto de resultados a dez documento:
var notInResult = session.createQuery("from Movie where title not in (:first, :second)", Movie.class) .setParameter("first", "Romeo and Juliet") .setParameter("second", "Best in Show") .setMaxResults(10) .getResultList();for (var m : notInResult) { System.out.println("Title: " + m.getTitle());}var notInResult = entityManager.createQuery("select m from Movie m where m.title not in (:first, :second)", Movie.class) .setParameter("first", "Romeo and Juliet") .setParameter("second", "Best in Show") .setMaxResults(10) .getResultList();for (var m : notInResult) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado NOT IN anterior para o seguinte estágio $match:
{ "$match": { "title": { "$nin": [ "Romeo and Juliet", "Best in Show" ] } }}Como $nin corresponde a cada documento em relação a uma lista vazia de valores, title not in () corresponde a todos os documentos.
Observação
Limitações do NOT IN
A extensão Hibernate ORM suporta o predicado NOT IN apenas quando o valor à esquerda de NOT IN é um caminho do campo. A extensão Hibernate ORM não suporta predicados NOT IN que:
Use uma subquery como a lista de valores.
Teste um valor contra uma expressão com valor de array, como em
:value not in m.cast.
Observação
Semântica de Nulo
Os predicados de valor de linha seguem a semântica nula da linguagem de query do MongoDB em vez da lógica ternária do Hibernate ORM, portanto, um predicado NOT IN corresponde a documentos nos quais um componente é nulo ou está ausente. Para aprender mais, consulte a seção Compare valores de campo a nulo deste guia.
IsNull
O predicado IS NULL corresponde a documentos que possuem um campo específico com um valor nulo ou ausente.
Para comparar um campo com null usando um operador de comparação em vez de um predicado, consulte a seção Comparar valores de campo com nulo deste guia.
O exemplo a seguir usa o predicado IS NULL para recuperar documentos que têm um valor cast ausente ou null da coleção sample_mflix.movies:
var isNullResult = session.createQuery("from Movie where cast is null", Movie.class) .getResultList();for (var m : isNullResult) { System.out.println("Title: " + m.getTitle());}var isNullResult = entityManager.createQuery("select m from Movie m where m.cast is null", Movie.class) .getResultList();for (var m : isNullResult) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado IS NULL anterior para o estágio $match a seguir, que corresponde a documentos onde o campo é explicitamente null ou está ausente:
{ "$match": { "cast": { "$eq": null } }}IS NOT NULL
O predicado IS NOT NULL corresponde a documentos que têm um campo com um valor não nulo ou não ausente.
O exemplo a seguir usa o predicado IS NOT NULL para recuperar documentos que têm um valor directors da coleção sample_mflix.movies:
var isNotNullResult = session.createQuery("from Movie where directors is not null", Movie.class) .getResultList();for (var m : isNotNullResult) { System.out.println("Title: " + m.getTitle());}var isNotNullResultEm = entityManager.createQuery("select m from Movie m where m.directors is not null", Movie.class) .getResultList();for (var m : isNotNullResultEm) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado IS NOT NULL anterior para o estágio $match a seguir, que corresponde a documentos onde o campo existe e não é explicitamente null:
{ "$match": { "directors": { "$ne": null } }}semelhante a
O predicado LIKE diferencia maiúsculas de minúsculas e corresponde a documentos onde um valor de campo corresponde a um padrão especificado. O padrão é aplicado a todo o valor do campo e pode usar os seguintes caracteres wildcard:
%: Corresponde a zero ou mais caracteres._: Corresponde exatamente a um caractere.
Para corresponder a um prefixo, inclua % no final do padrão e, para corresponder a um sufixo, inclua % no início do padrão.
Dica
Escapar caracteres wildcard
Se você quiser corresponder a % ou _ como um caractere literal, use a cláusula ESCAPE. Por exemplo, title like '100!%' escape '!' corresponde ao valor "100%". Você pode usar ESCAPE com %, _ ou o próprio caractere de escape. Se você usá-lo com qualquer outro caractere ou deixá-lo no final do padrão, a extensão Hibernate ORM lança um IllegalArgumentException.
O exemplo a seguir usa o predicado LIKE para recuperar documentos que têm um valor title que começa com "W", seguido por qualquer caractere único e depois "r", da coleção sample_mflix.movies:
var likeResult = session.createQuery("from Movie where title like 'W_r%'", Movie.class) .getResultList();for (var m : likeResult) { System.out.println("Title: " + m.getTitle());}var likeResultEm = entityManager.createQuery("select m from Movie m where m.title like 'W_r%'", Movie.class) .getResultList();for (var m : likeResultEm) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado LIKE anterior para o seguinte estágio $match:
{ "$match": { "title": { "$regex": /^W.r.*$/s } }}Observação
Limitações do predicado LIKE
O valor que você compara com LIKE deve ser um literal string, como '%War%'. A extensão Hibernate ORM não oferece suporte a um parâmetro vinculado (like :pattern), outro campo (like m.plot) ou um valor computado (like concat('War', '%')) para o padrão, e gera um FeatureNotSupportedException se você usar um.
Para aprender mais sobre o predicado HQL LIKE, consulte Um Guia da linguagem de query do Hibernate na documentação do ORM do Hibernate.
NOT LIKE
O predicado NOT LIKE corresponde a documentos nos quais um valor de campo não corresponde ao padrão especificado. A extensão Hibernate ORM nega o filtro $regex que o predicado LIKE produz e usa o mesmo comportamento e restrições de correspondência de padrão que o predicado LIKE.
O exemplo a seguir usa o predicado NOT LIKE para recuperar documentos que têm um valor title que não começa com "The" da coleção sample_mflix.movies. Como o predicado corresponde à maioria dos documentos, o exemplo chama o método setMaxResults() para limitar o conjunto de resultados a cinco documentos:
var notLikeResult = session.createQuery("from Movie where title not like 'The%'", Movie.class) .setMaxResults(5) .getResultList();for (var m : notLikeResult) { System.out.println("Title: " + m.getTitle());}var notLikeResultEm = entityManager.createQuery("select m from Movie m where m.title not like 'The%'", Movie.class) .setMaxResults(5) .getResultList();for (var m : notLikeResultEm) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado NOT LIKE anterior para o seguinte estágio $match:
{ "$match": { "$nor": [ { "title": { "$regex": /^The.*$/s } } ] }}ILIKE
O predicado ILIKE é a forma que não diferencia maiúsculas de minúsculas do predicado LIKE. A extensão Hibernate ORM marca o filtro $regex que o predicado LIKE produz como não diferenciando maiúsculas de minúsculas e usa o mesmo comportamento de correspondência de padrão e restrições que o predicado LIKE.
O exemplo a seguir usa o predicado ILIKE para recuperar documentos que têm um valor title contendo "Star" da coleção sample_mflix.movies:
var ilikeResult = session.createQuery("from Movie where title ilike '%Star%'", Movie.class) .getResultList();for (var m : ilikeResult) { System.out.println("Title: " + m.getTitle());}var ilikeResultEm = entityManager.createQuery("select m from Movie m where m.title ilike '%Star%'", Movie.class) .getResultList();for (var m : ilikeResultEm) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado ILIKE anterior para o seguinte estágio $match:
{ "$match": { "title": { "$regex": /^.*Star.*$/is } }}NOT ILIKE
O predicado NOT ILIKE é a forma que não diferencia maiúsculas de minúsculas do predicado NOT LIKE. A extensão Hibernate ORM nega o filtro $regex que não diferencia maiúsculas de minúsculas que o predicado ILIKE produz e usa o mesmo padrão de correspondência e restrições que o predicado LIKE.
O exemplo a seguir usa o predicado NOT ILIKE para recuperar documentos que têm um valor title que não contém "The" da coleção sample_mflix.movies. Como o predicado corresponde à maioria dos documentos, o exemplo chama o método setMaxResults() para limitar o conjunto de resultados a cinco documentos:
var notIlikeResult = session.createQuery("from Movie where title not ilike '%The%'", Movie.class) .setMaxResults(5) .getResultList();for (var m : notIlikeResult) { System.out.println("Title: " + m.getTitle());}var notIlikeResultEm = entityManager.createQuery("select m from Movie m where m.title not ilike '%The%'", Movie.class) .setMaxResults(5) .getResultList();for (var m : notIlikeResultEm) { System.out.println("Title: " + m.getTitle());}A extensão Hibernate ORM traduz o predicado NOT ILIKE anterior para o seguinte estágio $match:
{ "$match": { "$nor": [ { "title": { "$regex": /^.*The.*$/is } } ] }}Usar filtros lógicos
Você pode usar os seguintes operadores em suas declarações de query para combinar vários critérios de query:
and: Corresponder a todos os critériosor: Corresponder a qualquer critérionot: Não corresponde aos critérios
O exemplo a seguir recupera um documento que tem um valor de title de "The Godfather" e um valor de year de 1972 da coleção sample_mflix.movies:
var logicalResult = session.createQuery("from Movie where title = :t and year = :y", Movie.class) .setParameter("t", "The Godfather") .setParameter("y", 1972) .getSingleResult();System.out.println("Title: " + logicalResult.getTitle());var logicalResult = entityManager.createQuery("select m from Movie m where m.title = :t and m.year = :y", Movie.class) .setParameter("t", "The Godfather") .setParameter("y", 1972) .getSingleResult();System.out.println("Title: " + logicalResult.getTitle());Executar queries de um campo de chave primária
Para recuperar um documento com base em seu valor ObjectId, você pode passar esse valor como argumento para o método get(), se estiver usando uma sessão, ou o método find(), se estiver usando um gerenciador de entidades .
O exemplo a seguir recupera um documento da coleção sample_mflix.movies por seu valor ObjectId:
var movieById = session.get(Movie.class, new ObjectId("573a13a8f29313caabd1d53c"));var movieById = entityManager.find(Movie.class, new ObjectId("573a13a8f29313caabd1d53c"));Fazer consulta de um documento incorporado
Você pode representar documento incorporado do MongoDB criando @Struct agregados incorporáveis. Você pode então usar a extensão Hibernate ORM para buscar @Struct agregados incorporáveis associados a entidades pai específicas.
Dica
Para aprender mais sobre como representar documento incorporado, consulte o guia Criar entidades.
O exemplo a seguir recupera documentos que têm um valor title de "Hairspray" da coleção sample_mflix.movies. Em seguida, o código obtém o campo awards , que armazena o Awards @Struct agregado incorporável e imprime o campo wins do tipo Awards incorporável:
var embeddedResult = session.createQuery("select awards from Movie where title = :title", Awards.class) .setParameter("title", "Hairspray") .getResultList();for (var a : embeddedResult) { System.out.println("Award wins: " + a.getWins());}var embeddedResult = entityManager.createQuery("select m.awards from Movie m where m.title = :title", Awards.class) .setParameter("title", "Hairspray") .getResultList();for (var a : embeddedResult) { System.out.println("Award wins: " + a.getWins());}Query um campo em um documento incorporado
Você pode referenciar um campo em um tipo incorporável usando uma expressão de caminho pontilhado nas cláusulas SELECT, WHERE, ORDER BY e UPDATE de uma query HQL ou JPQL. Você também pode encadear vários nomes incorporáveis em uma expressão de caminho para referenciar um campo em um incorporável aninhado dentro de outro incorporável.
Importante
Limitações de query
As expressões de caminho não suportam campos incorporáveis que usam a anotação @ColumnTransformer para definir uma expressão de leitura personalizada.
A extensão Hibernate ORM também rejeita os seguintes mapeamentos incorporáveis de agregação @Struct quando cria o modelo de entidade:
Um embeddable de agregação
@Structusado como um campo@IdUma hierarquia incorporável de agregação
@Structpolimórfica
Você não pode usar uma expressão de caminho para referenciar um campo nesses tipos.
O exemplo a seguir usa uma expressão de caminho para filtrar documentos na coleção sample_mflix.movies. Existem dois filmes "Hairspray" na coleção sample_mflix.movies. Um filme "Hairspray" é de 1998 e o outro é de 2007. A query corresponde a documentos que têm um valor "Hairspray" para title e um valor 10 maior que awards.wins:
var matchingDocument = session.createQuery("from Movie where title = :title and awards.wins > :minWins", Movie.class) .setParameter("title", "Hairspray") .setParameter("minWins", 10) .getResultList();for (var m : matchingDocument) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}var matchingDocument = entityManager.createQuery("select m from Movie m where m.title = :title and m.awards.wins > :minWins", Movie.class) .setParameter("title", "Hairspray") .setParameter("minWins", 10) .getResultList();for (var m : matchingDocument) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}Query em elementos de um array incorporado
Quando um campo da sua entidade armazena um array de @Struct aggregate embeddables, você pode usar uma subconsulta EXISTS para corresponder a documentos pai nos quais pelo menos um elemento desse array atenda aos seus critérios. A extensão Hibernate ORM traduz a subconsulta para o operador $elemMatch do MongoDB, que aplica todos os critérios ao mesmo elemento de array.
Dados de amostra
Observação
Use o banco de dados sample_restaurants para esta seção
Os exemplos nesta seção usam a coleção sample_restaurants.restaurants em vez da coleção sample_mflix.movies usada em outras partes deste guia.
Para executar esses exemplos, conecte-se ao banco de dados sample_restaurants em sua string de conexão. Para saber mais sobre o banco de dados sample_restaurants, consulte os conjuntos de dados de amostra do Atlas.
A seguinte entidade Restaurant mapeia para a coleção restaurants e armazena uma lista de Grade incorporáveis em seu campo grades:
package org.example;
import com.mongodb.hibernate.annotations.ObjectIdGenerator;import jakarta.persistence.Column;import org.bson.types.ObjectId;import java.util.List;
import jakarta.persistence.Entity;import jakarta.persistence.Id;import jakarta.persistence.Table;
@Entity@Table(name = "restaurants")public class Restaurant { @Id @ObjectIdGenerator @Column(name = "_id") private ObjectId id; private String name; private String borough; private List<Grade> grades;
public Restaurant(String name, String borough, List<Grade> grades) { this.name = name; this.borough = borough; this.grades = grades; }
public Restaurant() {
}
public ObjectId getId() { return id; }
public void setId(ObjectId id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getBorough() { return borough; }
public void setBorough(String borough) { this.borough = borough; }
public List<Grade> getGrades() { return grades; }
public void setGrades(List<Grade> grades) { this.grades = grades; }
}O seguinte Grade @Struct incorporável agregado representa cada elemento do array grades:
package org.example;import jakarta.persistence.*;import org.hibernate.annotations.Struct;
@Embeddable@Struct(name = "Grade")public class Grade { private String grade; private int score;
public Grade() { }
public Grade(String grade, int score) { this.grade = grade; this.score = score; }
public String getGrade() { return grade; }
public void setGrade(String grade) { this.grade = grade; }
public int getScore() { return score; }
public void setScore(int score) { this.score = score; }
}Dica
Para aprender mais sobre arrays de embeddables, consulte Dados incorporados no guia Criar entidades.
Os documentos na coleção restaurants se assemelham ao seguinte:
{ "_id": { "$oid": "5eb3d668b31de5d588f4292a" }, "name": "Morris Park Bake Shop", "borough": "Bronx", "cuisine": "Bakery", "grades": [ { "date": { "$date": 1393804800000 }, "grade": "A", "score": 2 }, { "date": { "$date": 1299715200000 }, "grade": "B", "score": 14 } ]}Exemplo
O exemplo a seguir recupera restaurantes que têm pelo menos um elemento de array grades com um valor grade de "B" e um valor score igual a 12. Como ambos os critérios aparecem na mesma subconsulta, eles devem corresponder ao mesmo elemento de array:
var existsResult = session.createQuery( "from Restaurant r where exists (select g.grade from r.grades g where g.grade = :grade and g.score = :score)", Restaurant.class) .setParameter("grade", "B") .setParameter("score", 12) .getResultList();for (var r : existsResult) { System.out.println("Name: " + r.getName());}var existsResultEm = entityManager.createQuery( "select r from Restaurant r where exists (select g.grade from r.grades g where g.grade = :grade and g.score = :score)", Restaurant.class) .setParameter("grade", "B") .setParameter("score", 12) .getResultList();for (var r : existsResultEm) { System.out.println("Name: " + r.getName());}A extensão Hibernate ORM traduz a subconsulta EXISTS anterior para o seguinte estágio $match:
{ "$match": { "grades": { "$elemMatch": { "grade": { "$eq": "B" }, "score": { "$eq": 12 } } } }}Executar query de um campo de array
A extensão Hibernate ORM suporta as seguintes funções para consultar campos de array:
array_contains(): Corresponde a documentos em que um campo de array contém um valor especificadoarray_contains_nullable(): Corresponde a documentos onde um campo de array contém um valor especificado, incluindo valoresnullarray_includes(): Corresponde a documentos onde um campo de array inclui outro valor de arrayarray_includes_nullable(): Corresponde a documentos onde um campo de array inclui outro valor de array, incluindo valoresnull
Dica
Para aprender mais sobre as funções de array, consulte Funções para lidar com arrays no guia do usuário do Hibername ORM.
O exemplo a seguir usa a função array_contains() para recuperar documentos que têm o valor "Kathryn Hahn" no campo de array cast da coleção sample_mflix.movies:
var arrayResult = session.createQuery("from Movie where array_contains(cast, :actor)", Movie.class) .setParameter("actor", "Kathryn Hahn") .getResultList();for (var m : arrayResult) { System.out.println("Title: " + m.getTitle());}var arrayResult = entityManager.createQuery("select m from Movie m where array_contains(m.cast, :actor)", Movie.class) .setParameter("actor", "Kathryn Hahn") .getResultList();for (var m : arrayResult) { System.out.println("Title: " + m.getTitle());}Use funções de agregação
Você pode usar funções de agregação em queries HQL e JPQL para agrupar e resumir resultados de query, ou para aplicar um filtro a resultados agrupados usando uma cláusula HAVING. HQL e JPQL suportam as seguintes funções de agregação:
count()sum()avg()min()max()
Observação
Requisitos de GROUP BY
As funções de agregação exigem uma cláusula GROUP BY. Uma query que usa uma função de agregação sem agrupar os resultados, como select count(*) from Movie, ainda não é compatível. Campos não agregados na cláusula SELECT também devem aparecer na cláusula GROUP BY.
O exemplo a seguir agrupa filmes lançados entre 1920 e 1924 por ano. Para cada ano, ele retorna o número de filmes e o tempo de execução total de todos os filmes. A cláusula HAVING inclui apenas os anos cujos filmes têm um tempo de execução total superior a 300 minutos e ordena os resultados por ano.
var aggregateResult = session.createQuery( "select year, count(*), sum(runtime) from Movie where year between 1920 and 1924 " + "group by year having sum(runtime) > 300 order by year", Object[].class) .getResultList();for (var row : aggregateResult) { System.out.println("Year: " + row[0] + ", Count: " + row[1] + ", Total runtime: " + row[2]);}var aggregateResult = entityManager.createQuery( "select m.year, count(m), sum(m.runtime) from Movie m where m.year between 1920 and 1924 " + "group by m.year having sum(m.runtime) > 300 order by m.year", Object[].class) .getResultList();for (var row : aggregateResult) { System.out.println("Year: " + row[0] + ", Count: " + row[1] + ", Total runtime: " + row[2]);}Resumir valores distintos
Para resumir apenas os valores distintos de um campo, inclua a palavra-chave distinct dentro da função de agregação. Você pode usar distinct com as funções de agregação count(), sum(), avg(), min() e max().
count(distinct x) ignora valores nulos, portanto, conta apenas os valores distintos não nulos de x. Para min() e max(), a palavra-chave distinct não altera o resultado.
O exemplo a seguir agrupa filmes lançados entre 1998 e 2000 por ano. Para cada ano, ele retorna o número de filmes e o número de títulos distintos, e ordena os resultados por ano:
var distinctResult = session.createQuery( "select year, count(*), count(distinct title) from Movie where year between 1998 and 2000 " + "group by year order by year", Object[].class) .getResultList();for (var row : distinctResult) { System.out.println("Year: " + row[0] + ", Count: " + row[1] + ", Distinct titles: " + row[2]);}var distinctResult = entityManager.createQuery( "select m.year, count(m), count(distinct m.title) from Movie m where m.year between 1998 and 2000 " + "group by m.year order by m.year", Object[].class) .getResultList();for (var row : distinctResult) { System.out.println("Year: " + row[0] + ", Count: " + row[1] + ", Distinct titles: " + row[2]);}Informações adicionais
Para saber mais sobre como executar outras operações em seus dados do MongoDB, consulte o guia Operações CRUD.
Para aprender a fazer query em entidades que estão vinculadas por uma associação, consulte o guia Unir entidades em coleções.
Para aprender como retornar parte de um valor de datetime ou renderizar um valor de datetime como uma string, consulte o guia Usar funções de datetime em queries.
Para saber mais sobre como usar HQL e JPQL para executar queries, consulte Um guia para a linguagem de query do Hibernate na documentação do Hibernate ORM.