$expr
定义
已更改在版本5.0.
兼容性
您可以在以下环境中使用$expr
:
MongoDB Atlas:云中MongoDB部署的全托管服务
MongoDB Enterprise:基于订阅的自托管MongoDB版本
MongoDB Community:开源、免费使用且自托管MongoDB版本
语法
{ $expr: { <expression> } }
参数可以是任何有效的表达式。
行为
$expr 在 $lookup 操作中
当 $expr
出现在作为 $match
阶段的一部分的 $lookup
子管道中时,$expr
可以引用由 $lookup
阶段定义的 let
变量。例如,请参阅 使用多个连接条件和相关子查询。
在$eq
、$lt
、$lte
、$gt
和$gte
比较运算符中,放置在$expr
运算符中的可以使用在$lookup
阶段引用的from
集合上的索引。限制
索引只能用于字段和常量之间的比较,因此
let
操作数必须解析为常量。例如,对
$a
和常量值之间的比较可以使用索引,但无法使用索引比较$a
和$b
。当
let
操作数解析为空或缺失值时,不使用索引进行比较。不使用多键索引。
示例
比较单个文档中的两个字段
$expr
可以包含比较同一文档中字段的表达式。
创建一个包含以下文档的monthlyBudget
集合
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 } ] )
以下操作使用$expr
来查找spent
金额超过budget
的文档
db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )
输出
{ _id : 1, category : "food", budget : 400, spent : 450 } { _id : 2, category : "drinks", budget : 100, spent : 150 } { _id : 5, category : "travel", budget : 200, spent : 650 }
使用 $expr 与条件语句
某些查询需要在定义查询过滤器时执行条件逻辑。聚合管道提供了$cond
运算符来表示条件语句。通过使用$expr
与$cond
运算符,可以为您的查询语句指定条件过滤器。
创建一个包含以下文档的示例supplies
集合
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") } ] )
假设下个月即将到来的销售活动中,您想对价格进行折扣,使得
如果
qty
大于或等于100,则折扣价格为price
的0.5倍。如果
qty
小于100,则折扣价格为price
的0.75倍。
在应用折扣之前,您希望知道哪些supplies
集合中的项目折扣价格低于5
。
以下示例使用$expr
与$cond
来根据qty
计算折扣价格,并使用$lt
来返回计算后的折扣价格低于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") ] } });
以下表格显示了每个文档的折扣价格以及折扣价格是否低于NumberDecimal("5")
(即文档是否满足查询条件)。
文档 | 折扣价格 | < 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 |
db.collection.find()
操作返回计算后的折扣价格低于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") }
尽管 $cond
计算了一个有效的折扣价格,但这个价格并没有反映在返回的文档中。相反,返回的文档代表的是其原始状态下的匹配文档。查找操作没有返回 binder
或 legal pad
文档,因为它们的折扣价格大于 5
。