$expr
Definição
Alterado na versão 5.0.
$expr
Permite o uso de expressões dentro de um predicado 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: { <expression> } }
O argumento pode ser qualquer expressão válida.
Comportamento
$expr em operações de $lookup
Quando $expr
aparece em um estágio $match
que faz parte de um subpipeline $lookup
, $expr
pode se referir a variáveis let
definidas pelo estágio $lookup
. Para obter um exemplo, consulte Usar várias condições de junção e uma subquery correlacionada.
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
$expr
pode conter expressões que comparam campos do mesmo documento.
Crie uma coleção monthlyBudget
com estes 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" ] } } )
Saída:
{ _id : 1, category : "food", budget : 400, spent : 450 } { _id : 2, category : "drinks", budget : 100, spent : 150 } { _id : 5, category : "travel", budget : 200, spent : 650 }
Use $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 declarações condicionais. Ao usar $expr
com o operador $cond
, você pode especificar um filtro condicional para sua declaração de consulta.
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 $lt
para retornar documentos cujo preço com 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": "notebook", "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
.