MongoDb:在不同情况下搜索范围内的值

MongoDb:在不同情况下搜索范围内的值,mongodb,Mongodb,首先 我们有以下数据库记录 { _id:1, values: [ 1 ,5 ,6 ,8]}, { _id:2, values: [5 ,7 ,8,10 ,40 ,1]}, { _id:3, values: [50 ,60 ,5 ,1 ]} {_id:1, from: 1, to:100}, {_id:2, from: 101, to:200}, {_id:3, from: 201, to:300}, {_id:4, from: 301, to:400} ... 我需要查询所有包含8-10范围

首先

我们有以下数据库记录

{ _id:1, values: [ 1 ,5 ,6 ,8]},
{ _id:2, values: [5 ,7 ,8,10 ,40 ,1]},
{ _id:3, values: [50 ,60 ,5 ,1 ]}
{_id:1, from: 1, to:100},
{_id:2, from: 101, to:200},
{_id:3, from: 201, to:300},
{_id:4, from: 301, to:400} ...
我需要查询所有包含8-10范围内“值”的记录。结果必须是
{u id:1},{u id:2}

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

第二

我们有以下数据库记录

{ _id:1, values: [ 1 ,5 ,6 ,8]},
{ _id:2, values: [5 ,7 ,8,10 ,40 ,1]},
{ _id:3, values: [50 ,60 ,5 ,1 ]}
{_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在到范围内的记录。结果{u id:3}

query({from:{'$lte':205},to:{'$gte':205})
非常慢,根本不使用任何索引
{from:1,to:1}

我有点困惑。有人能帮忙吗

谢谢。

案例1:数组值范围查询 编辑:我使用错误的值进行了测试

在数组值上使用条件运算符(和隐式运算符),只需匹配一个条件即可返回文档

所以

  • _id:1匹配$lte和$gte子句:OK
  • _id:2匹配$lte和$gte子句:OK
  • _id:3只匹配$lte(5<10和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,
...
}
如果要为此查询使用索引,可以按如下方式执行:

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"
}
for(var i=0;i db.test\u col.ensureIndex({from:1,to:1})
>db.test_col.count()
120002
>db.test_col.find({from:{$gte:3},to:{$lt:60})
{
“光标”:“b将光标从_1_移动到_1”,
“isMultiKey”:错误,
“n”:69741,
“nscannedObjects”:69902,
“未扫描”:116563,
“扫描者”:错误,
“indexOnly”:错误,
“NYELDS”:0,
“跳过”:0,
“米利斯”:340,
“指数边界”:{
“发件人”:[
[
3.
1.7976931348623157e+308
]
],
“致”:[
[
-1.7976931348623157e+308,
60
]
]
},
“服务器”:“new-host-2.主页:27017”
}
在案例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范围内。

我知道这一点很晚,但正如建议的那样,没有必要更改模式,因为这可能会帮助像我这样的人在以后的时间点遇到:

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

db.getCollection('your collection').find({values :{$elemMatch :{$gte: 8, $lt: 10}}}, {_id:1})
基本上,这里我们使用$elemMatch将两个条件包装在同一数组字段值上,并使用第二个过滤器/条件进行查找。find是一个投影,表示输出应仅包含\u id


感谢其他人的回答/帮助。

您确定在范围查询中谓词中没有任何其他字段吗?您使用的是什么版本的MongoDB?是的,我们谈论的是2.2。在案例1中,如果您在第二条记录中插入0值-查询将返回两条记录。在案例2中,120000条记录的340ms变慢。在我的案例中,表中有2500条记录,000条记录,大约需要10秒。你所说的查询是真正的查询?或者你只是简化了它来解释你的问题?我这么说是因为我在本地执行了你的查询,并得到了预期的行为,正如我在帖子中所说的。是的,简化了。但是看看我的答案和你的例子。修复了!我已经测试过了,你是对的。我使用$elemMatch为此添加了一个解决方案,但您需要更改架构。[{'value':0},{'value':5},{'value':6}]?mongos>db.col2.find({'elemMatch':{values:{$lte:3,$gte:1}})mongos>db.col2.find({'elemMatch':{$values:{$lte 3},values:{$gte:1})返回nothingdb.col2.find($elemMatch':{$lte 3:values:})-->这在技术上不起作用,因为在同一个字段上执行两个不同的操作不受支持,$elemMatch存在的原因相同!!请检查我的答案。。