Docs HomeMongoDB Manual

$expr

Definition定义

Changed in version 5.0.5.0版更改。

$expr

Allows the use of aggregation expressions within the query language.允许在查询语言中使用聚合表达式

$expr has the following syntax:具有以下语法:

{ $expr: { <expression> } }

The arguments can be any valid aggregation expression. 参数可以是任何有效的聚合表达式For more information, see Expressions.有关详细信息,请参阅表达式

Behavior行为

$expr can build query expressions that compare fields from the same document in a $match stage.可以构建查询表达式来比较$match阶段中同一文档中的字段。

If the $match stage is part of a $lookup stage, $expr can compare fields using let variables. See Perform Multiple Joins and a Correlated Subquery with $lookup for an example.如果$match阶段是$lookup阶段的一部分,$expr可以使用let变量比较字段。有关示例,请参阅使用$lookup执行多个联接和关联子查询。

The $eq, $lt, $lte, $gt, and $gte comparison operators placed in an $expr operator can use an index on the from collection referenced in a $lookup stage. 放置在$expr运算符中的$eq$lt$lte$gt$gte比较运算符可以对$lookup阶段中引用的from集合使用索引。Limitations:限制:

  • Multikey indexes are not used.不使用多键索引
  • Indexes are not used for comparisons where the operand is an array or the operand type is undefined.如果操作数是数组或操作数类型未定义,则不将索引用于比较。
  • Indexes are not used for comparisons with more than one field path operand.索引不用于与多个字段路径操作数进行比较。

Examples实例

Compare Two Fields from A Single Document比较单个文档中的两个字段

Consider an monthlyBudget collection with the following documents:考虑一个包含以下文档的monthlyBudget集合:

{ "_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 }

The following operation uses $expr to find documents where the spent amount exceeds the budget:以下操作使用$expr查找spent(支出)金额超过budget(预算)的文档:

db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )

The operation returns the following results:该操作返回以下结果:

{ "_id" : 1, "category" : "food", "budget" : 400, "spent" : 450 }
{ "_id" : 2, "category" : "drinks", "budget" : 100, "spent" : 150 }
{ "_id" : 5, "category" : "travel", "budget" : 200, "spent" : 650 }

Using $expr With Conditional Statements$expr与条件语句一起使用

Some queries require the ability to execute conditional logic when defining a query filter. 在定义查询筛选器时,某些查询需要执行条件逻辑的能力。The aggregation pipeline provides the $cond operator to express conditional statements. 聚合管道提供$cond运算符来表达条件语句。By using $expr with the $cond operator, you can specify a conditional filter for your query statement.通过将$expr$cond运算符一起使用,可以为查询语句指定条件筛选器。

Create a sample supplies collection with the following documents:使用以下文档创建样例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") }
])

Assume that for an upcoming sale next month, you want to discount the prices such that:假设下个月即将进行的销售,您希望对价格进行折扣,以便:

  • If qty is greater than or equal to 100, the discounted price will be 0.5 of the price.如果qty大于或等于100,折扣价格将为price0.5
  • If qty is less than 100, the discounted price is 0.75 of the price.如果qty少于100,折扣价格为price0.75

Before applying the discounts, you would like to know which items in the supplies collection have a discounted price of less than 5.在应用折扣之前,您想知道supplies集合中哪些商品的折扣价格低于5

The following example uses $expr with $cond to calculate the discounted price based on the qty and $lt to return documents whose calculated discount price is less than NumberDecimal("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") ] } });

The following table shows the discounted price for each document and whether discounted price is less than NumberDecimal("5") (i.e. whether the document meets the query condition).下表显示了每张单据的折扣价,以及折扣价是否小于NumberDecimal("5")(即单据是否满足查询条件)。

Document文档Discounted Price折扣价< 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

The db.collection.find() operation returns the documents whose calculated discount price is less than NumberDecimal("5"):操作返回计算出的折扣价格小于NumberDecimal("5")的文档: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") }

Even though $cond calculates an effective discounted price, that price is not reflected in the returned documents. Instead, the returned documents represent the matching documents in their original state. 即使$cond计算了一个有效的折扣价格,该价格也不会反映在返回的文档中。相反,返回的文档表示原始状态下的匹配文档。The find operation did not return the binder or legal pad documents, as their discounted price was greater than 5.查找操作没有返回binderlegal pad文档,因为它们的折扣价大于5