$expr
Definição
Alterado na versão 5.0.
$expr
Permite o uso de expressões de agregação dentro da linguagem de query.
Compatibilidade
Você pode utilizar o $expr
para implantações hospedadas nos seguintes ambientes:
MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Sintaxe
$expr
tem a seguinte sintaxe:
{ $expr: { <expression> } }
Os argumentos podem ser qualquer expressão de agregação válida . Para obter mais informações, consulte expressão.
Comportamento
$expr
pode criar expressões de query que comparam campos do mesmo documento em um estágio $match
.
Se o estágio $match
fizer parte de um estágio $lookup
, $expr
poderá comparar campos usando variáveis let
. Consulte Realizar várias uniões e uma subquery correlacionada com $lookup
para obter um exemplo.
Os operadores de comparação $eq
, $lt
, $lte
, $gt
e $gte
colocados em um operador $expr
podem utilizar um índice na coleção from
referenciada em um estágio $lookup
. Limitações:
Os índices só podem ser usados para comparações entre campos e constantes, portanto, o operando
let
deve ser resolvido para uma constante.Por exemplo, uma comparação entre
$a
e um valor constante pode usar um índice, mas uma comparação entre$a
e$b
não pode.Os índices não são usados para comparações onde o operando
let
resolve para um valor vazio ou ausente.Índices multichave não são usados.
Exemplos
Comparar dois campos de um único documento
Considere uma collection monthlyBudget
com os seguintes documentos:
db.monthlyBudget.insertMany( [ { _id : 1, category : "food", budget : 400, spent : 450 }, { _id : 2, category : "drinks", budget : 100, spent : 150 }, { _id : 3, category : "clothes", budget : 100, spent : 50 }, { _id : 4, category : "misc", budget : 500, spent : 300 }, { _id : 5, category : "travel", budget : 200, spent : 650 } ] )
A operação a seguir usa $expr
para localizar documentos em que o valor spent
excede budget
:
db.monthlyBudget.find( { $expr: { $gt: [ $spent , $budget ] } } )
A operação retorna os seguintes resultados:
{ _id : 1, category : "food", budget : 400, spent : 450 } { _id : 2, category : "drinks", budget : 100, spent : 150 } { _id : 5, category : "travel", budget : 200, spent : 650 }
Usando $expr
com declarações condicionais
Algumas queries exigem a capacidade de executar lógica condicional ao definir um filtro de query. O pipeline de agregação fornece o operador $cond
para expressar instruções condicionais. Usando $expr
com o operador $cond
, você pode especificar um filtro condicional para sua declaração de query.
Criar uma coleção supplies
de amostra com os seguintes documentos:
db.supplies.insertMany( [ { _id : 1, item : "binder", qty : NumberInt("100"), price : NumberDecimal("12") }, { _id : 2, item : "notebook", qty : NumberInt("200"), price : NumberDecimal("8") }, { _id : 3, item : "pencil", qty : NumberInt("50"), price : NumberDecimal("6") }, { _id : 4, item : "eraser", qty : NumberInt("150"), price : NumberDecimal("3") }, { _id : 5, item : "legal pad", qty : NumberInt("42"), price : NumberDecimal("10") } ] )
Suponha que, para uma futura venda no próximo mês, você queira descontar os preços de forma que:
Se
qty
for maior ou igual a 100, o preço com desconto seja 0,5 doprice
.Se
qty
for inferior a 100, o preço com desconto seja 0,75 doprice
.
Antes de aplicar os descontos, você gostaria de saber quais itens da collection supplies
têm um preço com desconto inferior a 5
.
O exemplo a seguir usa $expr
com $cond
para calcular o preço com desconto com base em qty
e usa $lt
para retornar documentos cujo preço de desconto calculado é menor que NumberDecimal("5")
:
// Aggregation expression to calculate discounted price let discountedPrice = { $cond: { if: { $gte: ["$qty", 100] }, then: { $multiply: ["$price", NumberDecimal("0.50")] }, else: { $multiply: ["$price", NumberDecimal("0.75")] } } }; // Query the supplies collection using the aggregation expression db.supplies.find( { $expr: { $lt:[ discountedPrice, NumberDecimal("5") ] } });
A tabela a seguir mostra o preço com desconto para cada documento e se o preço com desconto é inferior a NumberDecimal("5")
(ou seja, se o documento atende à condição de query).
Documento | Preço com desconto | < NumberDecimal("5") |
---|---|---|
{"_id": 1, "item": "binder", "qty": 100, "price": NumberDecimal("12") } | NumberDecimal("6,00") | false |
{{"_id": 2, "item": "noteboook", "qty": 200, "price": NumberDecimal("8") } | NumberDecimal("4,00") | true |
{"_id": 3, "item": "pencil", "qty": 50, "price": NumberDecimal("6") } | NumberDecimal("4,50") | true |
{"_id": 4, "item": "eraser", "qty": 150, "price": NumberDecimal("3") } | NumberDecimal("1,50") | true |
{"_id": 5, "item": "legal pad", "qty": 42, "price": NumberDecimal("10") } | NumberDecimal("7,50") | false |
A operação db.collection.find()
retorna os documentos cujo preço com desconto calculado é menor que NumberDecimal("5")
:
{ _id : 2, item : "notebook", qty : 200 , price : NumberDecimal("8") } { _id : 3, item : "pencil", qty : 50 , price : NumberDecimal("6") } { _id : 4, item : "eraser", qty : 150 , price : NumberDecimal("3") }
Embora $cond
calcule um preço com desconto efetivo, esse preço não é refletido nos documentos retornados. Em vez disso, os documentos retornados representam os documentos correspondentes em seu estado original. A operação de busca não retornou os documentos binder
ou legal pad
, pois o preço com desconto era maior que 5
.