【问题标题】:Mongo Query question $gt,$ltMongo 查询问题 $gt,$lt
【发布时间】:2011-02-11 06:24:45
【问题描述】:

我在下面有一个问题。我想要获取 4 到 6 之间的项目,所以只有 a:1 应该匹配,因为它在 b 中的值为 5。

> db.test.find({ b : { $gt :  4  }, b: {$lt : 6}});
{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 3, 4, 5 ] }
{ "_id" : ObjectId("4d54d0074364000000004332"), "a" : 2, "b" : [ 2, 4, 6, 8 ] }
>

有人能说出为什么 a:2 匹配这个查询吗?我真的不明白为什么它会被退回。

我也尝试了教程中指定的内容,但 id 似乎不起作用:

> db.test.find({ b : { $gt :  4, $lt : 6}});
{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 3, 4, 5 ] }
{ "_id" : ObjectId("4d54d0074364000000004332"), "a" : 2, "b" : [ 2, 4, 6, 8 ] }
>

这个是为了避免对 GT/GTE 造成任何混淆

> db.test.find({b: {$gt: 4.5, $lt: 5.5}});
{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 3, 4, 5 ] }
{ "_id" : ObjectId("4d54d0074364000000004332"), "a" : 2, "b" : [ 2, 4, 6, 8 ] }
>

只应返回 a:1。

按照建议,我尝试了 $elemMatch,但它似乎也不起作用(objectIds 不同,因为我在不同的机器上)

> db.test.find();
{ "_id" : ObjectId("4d5a24a5e82e00000000433f"), "a" : 1, "b" : [ 2, 3, 4, 5 ] }
{ "_id" : ObjectId("4d5a24bbe82e000000004340"), "a" : 2, "b" : [ 2, 4, 6, 8 ] }
> db.test.find({b: {$elemMatch: {$gt : 4, $lt: 6 }}});
>

没有文件被退回。

【问题讨论】:

  • 其实两个文档都应该返回,问题的意思是“给我所有b的值在4到6之间的文档”,这两个文档都满足。您能否更详细地解释它要查询的内容?为什么要找到第一个文档而不是第二个?
  • 正如你上面所说,我想要所有 b 介于 4 和 6 之间的文档。只有 a:1 满足这一点(不能同时满足两者),因为 a:2 不包含 4 和 6 之间的任何值(使用gt 和 lt 排除 4 和 6 本身,而 gte 和 lte 将包括它们)。我尝试了一个更清晰的不同查询(请参阅已编辑的问题),但它仍然无法正常工作......
  • 我明白你现在的意思了,我认为它是一个范围(范围通常包括第一个元素),但当然不是,它是严格的小于和大于。我已经删除了我的答案,因为现在很明显它是错误的。

标签: mongodb


【解决方案1】:

这是一个非常令人困惑的话题。我在 10gen 工作,我不得不花一些时间来解决它;)

让我们来看看查询引擎如何处理这个查询。

这里又是一个查询:

> db.test.find({ b : { $gt :  4, $lt : 6}});

当它到达看起来不应该匹配的记录时......

{ "_id" : ObjectId("4d54cff54364000000004331"), "a" : 1, "b" : [ 2, 4, 6, 8 ] }

匹配不是针对数组的每个元素,而是针对整个数组。

比较分三步进行:

第一步:找出所有b值大于4的文档

b: [2,4,6,8] 匹配,因为 6 & 8 大于 4

第 2 步:查找 b 值小于 6 的所有文档

b: [2,4,6,8] 匹配,因为 2 & 4 小于 6

第 3 步:找到在第 1 步和第 2 步中都匹配的文档集。

带有 b: [2,4,6,8] 的文档与第 1 步和第 2 步都匹配,因此它作为匹配项返回。请注意,在此步骤中也会对结果进行重复数据删除,因此不会返回两次相同的文档。

如果您希望查询应用于数组的单个元素,而不是整个数组,您可以使用 $elemMatch 运算符。例如

> db.temp.find({b: {$elemMatch: {$gt: 4, $lt: 5}}})
> db.temp.find({b: {$elemMatch: {$gte: 4, $lt: 5}}})
  { "_id" : ObjectId("4d558b6f4f0b1e2141b66660"), "b" : [ 2, 3, 4, 5, 6 ] }

【讨论】:

  • 感谢 Jared,您提供了精心布置的答案。但是,在尝试时,它似乎不起作用。 (我试过“db.test.find({b: {$elemMatch: {$gt : 4, $lt: 6 }}});”正如你所描述的。(有关详细信息,请参阅已编辑的问题)你能解释一下吗关于这个?
  • 奇怪。这个对我有用。 > db.array2.save({b:[2,3,4,5]}) > db.array2.save({b:[2,4,6,8]}) > db.array2.find({ b: {$elemMatch: {$gt: 4, $lt: 6}}}) { "_id" : ObjectId("4d5a9268ec5855af36625ed6"), "b" : [ 2, 3, 4, 5 ] } > 什么版本你在用 MongoDB 吗? $elemMatch 是在 1.3.1 中添加的,所以如果您仍在使用 1.2,它将无法正常工作。
  • 在这里不起作用。只需复制并粘贴您的查询(插入然后查询)。我有 1.6.5。看起来它可能是一个错误:jira.mongodb.org/browse/SERVER-1264
  • 啊。是的,你是对的。我在 1.7.5 中运行测试。当我在 1.6.5 中运行时,它不起作用。似乎这不会被反向移植。好消息是 1.8 即将发布,并将包含此修复。
  • 我必须查找 10gen 是什么:D
【解决方案2】:

$gt

Syntax: {field: {$gt: value} }

例如:

db.inventory.find( { qty: { $gt: 20 } } )

$lt

Syntax: {field: {$lt: value} }

例如:

db.inventory.find( { qty: { $lt: 20 } } )

eg2:

db.inventory.find({ qty : { $gt :  20, $lt : 60}});

【讨论】:

    【解决方案3】:
    .find( {$and:[ {b:{$gt:4}}, {b:{$lt:6}} ]} )
    

    【讨论】:

    • 没有。接受的答案中显示的语法是正确的,并且已经是“与”操作。这很简洁,是可读语法的一个坏例子。
    【解决方案4】:

    下面是详细文档,供大家理解,

    db.test.insertMany([
        {"_id":1, "x":11, "a":1, "b":[1]},
        {"_id":2, "x":15, "a":4, "b":[1,2,3]},
        {"_id":3, "x":19, "a":5, "b":[1,2,3,4,5]},
        {"_id":4, "x":13, "a":6, "b":[6,8,10]},
        {"_id":5, "x":16, "a":13, "b":[11]},
        {"_id":6, "x":18, "a":11, "b":[5]},
        {"_id":7, "x":15, "a":15, "b":[3,5,7]},
        {"_id":8, "x":12, "a":18, "b":[3,7,9]},
        {"_id":9, "x":14, "a":21, "b":[4,6]}
    ]);
    

    包含以下查询以明确比较,
    查询一:db.test.find({b: {$lt: 6}}); //(any element of b) < 6

    { "_id" : 1, "x" : 11, "a" : 1, "b" : [ 1 ] }
    { "_id" : 2, "x" : 15, "a" : 4, "b" : [ 1, 2, 3 ] }
    { "_id" : 3, "x" : 19, "a" : 5, "b" : [ 1, 2, 3, 4, 5 ] }
    { "_id" : 6, "x" : 18, "a" : 11, "b" : [ 5 ] }
    { "_id" : 7, "x" : 15, "a" : 15, "b" : [ 3, 5, 7 ] }
    { "_id" : 8, "x" : 12, "a" : 18, "b" : [ 3, 7, 9 ] }
    { "_id" : 9, "x" : 14, "a" : 21, "b" : [ 4, 6 ] }
    

    `

    查询 2:db.test.find({b: {$gt: 4}, b:{$lt : 6}});// it is translated to db.test.find({b:{$lt : 6}}); hence the outcome of Query-1 and Query-2 is the same.

    { "_id" : 1, "x" : 11, "a" : 1, "b" : [ 1 ] }
    { "_id" : 2, "x" : 15, "a" : 4, "b" : [ 1, 2, 3 ] }
    { "_id" : 3, "x" : 19, "a" : 5, "b" : [ 1, 2, 3, 4, 5 ] }
    { "_id" : 6, "x" : 18, "a" : 11, "b" : [ 5 ] }
    { "_id" : 7, "x" : 15, "a" : 15, "b" : [ 3, 5, 7 ] }
    { "_id" : 8, "x" : 12, "a" : 18, "b" : [ 3, 7, 9 ] }
    { "_id" : 9, "x" : 14, "a" : 21, "b" : [ 4, 6 ] }
    

    查询 3:db.test.find({b: {$gt: 4, $lt: 6}});

    { "_id" : 3, "a" : 5, "b" : [ 1, 2, 3, 4, 5 ] }//(element 5) > 4 and (element 5) < 6` => The matching element is same here element 5
    { "_id" : 6, "a" : 11, "b" : [ 5 ] }//(element 5) > 4 and (element 5) < 6 => The matching element is same here element 5
    { "_id" : 7, "a" : 15, "b" : [ 3, 5, 7 ] }//(element 5) > 4 and (element 5) < 6 => The matching element is same here element 5
    { "_id" : 8, "a" : 18, "b" : [ 3, 7, 9 ] }//(element 5) > 7 and (element 3) < 6 => The matching elements are different i.e. here element 5 and element 3
    { "_id" : 9, "a" : 21, "b" : [ 4, 6 ] }//(element 6) > 4 and (element 4) < 6 => The matching elements are different i.e. here element 4 and element 6
    

    查询 4:db.test.find({b: {$elemMatch: {$gt : 4, $lt: 6 }}});

    { "_id" : 3, "a" : 5, "b" : [ 1, 2, 3, 4, 5 ] }//(element 5) > 4 and (element 5) <6
    { "_id" : 6, "a" : 11, "b" : [ 5 ] }//(element 5) > 4 and (element 5) <6
    { "_id" : 7, "a" : 15, "b" : [ 3, 5, 7 ] }//(element 5) > 4 and (element 5) <6
    

    Query-3 和 Query-4 很有趣。
    查询 3:列出具有数组 b 元素 x>4 和元素 y 查询 4:列出具有数组 b 元素 x>4 和元素 y

    【讨论】:

      【解决方案5】:

      因为你没有检查文档。

      http://www.mongodb.org/display/DOCS/Advanced+Queries

      并检查页面上的“范围”。

      您的查询语法也不正确(与示例比较)

      您的问题的“为什么 a:2”部分也没有任何意义,因为您的查询不涉及“a”。如果要搜索 a:1,则必须将其包含在查询中。

      请记住,除非您使用 $or 运算符,否则默认情况下所有查询子句都是 AND 组合。

      【讨论】:

      • 另外:如果您对字段的子集感兴趣:mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields
      • 感谢您指出该页面上的范围示例。我看过该页面,但错过了范围部分。查询执行时语法显然是正确的,但我只是没有利用范围因素。 “为什么 a:2”确实很有意义,因为它唯一地标识了每一行,它不需要参与查询。我还应该指出,如果子句被解释为 AND,那么我的查询仍然应该正确地采用范围。所以谢谢你的链接,但不感谢你的粗鲁。
      • 是的。你很粗鲁。
      • 教程也不行:> db.test.find({ b : { $gt : 4, $lt : 6}}); {“_id”:ObjectId(“4d54cff54364000000004331”),“a”:1,“b”:[2,3,4,5]} {“_id”:ObjectId(“4d54d0074364000000004332”),“a”:2, "b" : [ 2, 4, 6, 8 ] } >
      • 另外检查 $elemMatch 运算符并一如既往地使用 $where 运算符
      猜你喜欢
      • 2017-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      • 2015-09-01
      • 2020-04-24
      • 2014-01-23
      • 2018-12-24
      相关资源
      最近更新 更多