Mongo $和选择器

时间:2016-02-12 09:22:09

标签: javascript mongodb meteor mongodb-query

mongo $和选择器如何工作?我无法获得正确的结果。

假设我有一个像这样的集合:

{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 5 }
{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 9 }
{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 34 }
{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 66 }

我运行查询:

var selectorMin = 9;
var selectorMax = 42;

ScrapReport.find({ $and: [ { quantity: { $gte: selectorMin }, quantity: { $lte: selectorMax } } ] })

我希望mongo只返回9和34但是由于某种原因它也会返回5和66.

我的查询有什么问题?

3 个答案:

答案 0 :(得分:4)

您的查询返回该示例中的所有文档,因为它首先查找的文档quantity >= 9即9,34和66 AND 将该查询与{{1}的文档相结合即34,9和5.它没有查找特定范围内的文档,但您的查询明确查找满足两个范围的所有文档,即

quantity <= 42

不是

Documents which satisfy "quantity >= 9"
+
Documents which satisfy "quantity <= 42"

只需将查询简化为

即可
Documents which satisfy "9 <= quantity <= 42"

这样,您可以指定MongoDB使用例如

过滤文档的范围
ScrapReport.find({ "quantity": { "$gte": selectorMin, "$lte": selectorMax } })

指定逗号分隔的表达式列表意味着隐式AND操作,并且当必须在多个表达式中指定相同的字段或运算符时,使用带 $and 运算符的显式AND。

答案 1 :(得分:3)

使用隐含的AND操作,就像建议的其他答案一样。但我想深入研究具体细节。 为什么您的查询无法正常工作?

为什么?为什么这个看似正确的查询对您的回复不是那么正确的结果?毕竟,无论您使用隐式还是显式AND操作都应该是您的选择的问题,无论您使用哪种形式,您都应该能够实现目标。 如何使用明确的AND操作进行查询?

让我们看一下AND操作的语法。

{ $and: [ { <expression1> }, { <expression2> } , ... , { <expressionN> } ] }

AND运算符的值应该是一个包含要在其上执行AND运算的表达式的数组。

第一眼看到你的查询后,一切看起来都很好。但是如果你花一点时间来深入研究,你会发现你的查询与AND语法不完全匹配。它在语法上仍然是正确的。毫无疑问。但它在逻辑上是不正确的。我将解释如何。

这是您的$and运算符值

{ $and: [ { quantity: { $gte: selectorMin }, quantity: { $lte: selectorMax } } ] }

您认为您有一个表达式quantity: { $gte: selectorMin }和一个表达式2 quantity: { $lte: selectorMax }。使用这些表达式的AND操作应返回数量为9和34的文档。但实际上,您拥有的只是一个表达式。密切注意牙套。您已在单个{}块中添加了这两个表达式。你看到了吗?如此有效,AND运算符没有第二个表达式可供使用。但AND运算符需要两个或多个表达式才能正常运行。

因此您的查询格式为

{ $and: [ { <expression1> } ] }

如果表单不正确,结果也会不正确。使用显式AND操作的正确查询将是

ScrapReport.find({ $and: [ { quantity: { $gte: selectorMin } }, { quantity: { $lte: selectorMax } } ] })

你看到了区别吗?尝试此查询,您将获得您期望的结果。

如果您对答案感到不满意并且很想知道Mongo如何解释您的第一个查询,请继续阅读。

考虑此查询

ScrapReport.find({ quantity: 9 })

您期望结果如何?如果您希望Mongo返回单个文档,其数量字段中的值为9,那么您是对的。这正是结果。现在考虑相同的查询,但有一点小麻烦。

ScrapReport.find({ quantity: 9, quantity: 5 })

现在的结果是什么?事情现在变得有趣了,是吧?如果执行此查询并查看结果,您仍将只看到一个文档。但是数量字段中的值是5.现在这很有趣!

ScrapReport.find({ quantity: 9, quantity: 5, quantity: 34 })

这个怎么样?结果仍然是单个文档,其数量字段中的值为34.您可以尝试其他组合。你会发现这是什么 -

  

在表达式中,如果多次引用某个字段,结果将由该表达式中该字段的最后一个引用确定。

现在将此概念应用于原始查询。已经指出,您有一个表达式,其中包含quantity: { $gte: selectorMin }quantity: { $lte: selectorMax }两个部分。因为在表达式中,您指的是同一个字段两次,所以只有最后一个字段是相关的。选择标准为quantity: { $lte: selectorMax }。结果将是3份文件,数量值为5,9和34.

如果您更换订单,即先写quantity: { $lte: selectorMax }然后再写quantity: { $gte: selectorMin },现在将由quantity: { $gte: selectorMin }确定选择条件。结果将是3份文件,数量值为9,34和66。

虽然这不是您的意图,但您的原始查询实际上是

ScrapReport.find({ quantity: { $gte: selectorMin }, quantity: { $lte: selectorMax } })

当你错过大括号或将它们添加到错误的位置时,它可以完全改变查询的含义。

  

道德 - 密切关注您在复杂查询中放置大括号的位置。

答案 2 :(得分:1)

实际上你有两个问题:

您的查询等同于以下内容:

ScrapReport.find( { "$and": [{ "quantity": { "$lte": selectorMax } } ] } )

甚至更好:

ScrapReport.find( { "quantity": { "$lte": selectorMax } } )

原因是因为JSON文档中允许使用重复键,但保留了给定键的最后一个值。

所以这只会返回“数量”小于或等于selectorMax的所有文件。

@ chridam的答案中已经提到了第二个问题,所以正确的查询是:

ScrapReport.find({ "quantity": { "$gte": selectorMin, "$lte": selectorMax } })