5

第一的。

我们在数据库中有以下记录

{ _id:1, values: [ 1 ,5 ,6 ,8]},
{ _id:2, values: [5 ,7 ,8,10 ,40 ,1]},
{ _id:3, values: [50 ,60 ,5 ,1 ]}

我需要查询包含 8 - 10 范围内的“值”的所有记录。结果必须是{_id:1},{_id:2}

query ({values:{'$gte':8,'$lte':10}})返回所有记录,结果不正确,因为 'values' 是数组!!

第二。

我们在数据库中有以下记录

{_id:1, from: 1, to:100},
{_id:2, from: 101, to:200},
{_id:3, from: 201, to:300},
{_id:4, from: 301, to:400} ...

我需要找到元素 205 在 from-to 范围内的记录。结果 {_id:3}

query({from:{'$lte':205},to:{'$gte':205})

非常慢,根本不使用任何索引{from:1,to:1}

我有点困惑。有人可以帮忙吗,拜托。

谢谢你。

4

3 回答 3

3

案例 1:对数组值的范围查询

编辑:我使用错误的值进行了测试。

正如文档所解释的,对数组值使用条件运算符(AND 隐式运算符)只需要匹配一个条件即可返回文档。

所以,

  • _id:1 匹配 $lte 和 $gte 子句:OK
  • _id:2 匹配 $lte 和 $gte 子句:OK
  • _id:3 仅匹配 $lte (5 < 10 and 1 < 10) 子句:不可以,但按文档说明的方式工作。

如果您需要使用此范围查询对数组值进行过滤,则必须使用对象包装这些值,如下所示:

db.test_col2.insert({values:[{v:1} ,{v:5 },{v:6} ,{v:8}]})
db.test_col2.insert({values:[{v:5 },{v:7} ,{v:8},{v:10 },{v:40} ,{v:1}]})
db.test_col2.insert({values: [{v:50} ,{v:60} ,{v:5} ,{v:1} ]})
db.test_col2.find({values: {$elemMatch:{v:{$lte:10, $gte:8}}} })

{"_id":ObjectId("51273098140d09d9105739b5"),"values":[{"v":1},{"v":5},{"v":6},{"v":8}]}
{"_id":ObjectId("51273098140d09d9105739b6"),"values":[{"v":5},{"v":7},{"v":8},{"v":10},{"v":40},{"v":1}]}

如果要为此查询使用索引,可以按如下方式进行:

db.test_col2.ensureIndex({"values.v":1})
db.test_col2.find({values: {$elemMatch:{v:{$lte:10, $gte:8}}} }).explain()
{
  "cursor": "BtreeCursor values.v_1",
  "isMultiKey": true,
...
}

案例 2:使用开放范围命中索引

如您所见,此查询按预期命中索引。

for(var i=0 ; i<120000 ; i++) {
... db.test_col.insert({from: (Math.random()*100)%100, to: (Math.random()*100)%100});
... }
> db.test_col.ensureIndex({from:1, to:1})
> db.test_col.count()
120002
> db.test_col.find({from:{$gte:3}, to:{$lt:60}}).explain()
{
    "cursor" : "BtreeCursor from_1_to_1",
    "isMultiKey" : false,
    "n" : 69741,
    "nscannedObjects" : 69902,
    "nscanned" : 116563,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 340,
    "indexBounds" : {
        "from" : [
            [
                3,
                1.7976931348623157e+308
            ]
        ],
        "to" : [
            [
                -1.7976931348623157e+308,
                60
            ]
        ]
    },
    "server" : "new-host-2.home:27017"
}
于 2013-02-21T23:07:39.420 回答
0

在案例 1 中:

MongoDB shell version: 2.2.0
connecting to: xxx:9900/test
mongos> db.col2.insert({values:[1,2,3]})
mongos> db.col2.insert({values:[0,5,6]})
mongos> db.col2.find({values:{$lte:3, $gte:1}})
{ "_id" : ObjectId("51272120d96837944b3a2097"), "values" : [ 1, 2, 3 ] }
{ "_id" : ObjectId("5127212bd96837944b3a2098"), "values" : [ 0, 5, 6 ] }

对我来说,它是不正确的。0 5 6 不在 1-3 范围内。

于 2013-02-22T07:44:48.213 回答
0

我知道这很晚,但建议不需要更改架构,因为这可能会帮助像我这样后来遇到的人:

案例 1:对数组值的范围查询

db.getCollection('your collection').find({values :{$elemMatch :{$gte: 8, $lt: 10}}}, {_id:1})

基本上在这里,我们使用 $elemMatch 将两个条件包装在相同的数组字段上,而 .find 的第二个过滤器/条件是一个投影,它表示输出应该只包含_id

感谢他人的回答/帮助..

于 2019-05-08T22:32:04.750 回答