查询抱怨缺少 2dsphere-index,但它就在那里
Posted
技术标签:
【中文标题】查询抱怨缺少 2dsphere-index,但它就在那里【英文标题】:Query complains about missing 2dsphere-index, but it's there 【发布时间】:2018-04-12 17:16:18 【问题描述】:当我执行以下代码时(一个更大的例子,归结为要领)
var mongoose = require("mongoose");
var LocationSchema = new mongoose.Schema(
userName: String,
loc:
'type': type: String, enum: "Point", default: "Point" ,
coordinates: type: [Number]
)
LocationSchema.index( category: 1, loc: "2dsphere" );
var Location = mongoose.model("location", LocationSchema);
var mongoDB = 'mongodb://user1:test@ds042417.mlab.com:42417/locationdemo';
mongoose.Promise = global.Promise;
mongoose.connect(mongoDB, useMongoClient: true );
var testUser = Location(
userName: "Tester",
loc: coordinates: [12.44, 55.69]
);
testUser.save(function (err)
if (err)
return console.log("UPPPPs: " + err);
console.log("User Saved, Try to find him:");
let query = Location.find(
loc:
$near:
$geometry:
type: "Point",
coordinates: [12.50, 55.71]
,
$maxDistance: 600000
)
query.exec(function (err, docs)
if (err)
return console.log("Err: " + err);
console.log("Found: " + JSON.stringify(docs))
)
);
我收到此错误:
Err: MongoError: 错误处理查询: ns=locationdemo.locationsTree: GEONEAR field=loc maxdist=600000 isNearSphere=0 种类: 项目: 规划器返回错误:无法找到 $geoNear 查询的索引
但索引在那里(见第 10 行)和下面 mlab 的屏幕截图。我究竟做错了什么?:
【问题讨论】:
您认为提供的答案中是否有某些内容无法解决您的问题?如果是这样,请对答案发表评论,以澄清究竟需要解决哪些尚未解决的问题。如果它确实回答了您提出的问题,请注意Accept your Answers您提出的问题 【参考方案1】:您违反了一般如何使用索引的规则。虽然确实有no restriction 认为“2dsphere”索引是复合索引中的“第一个”属性,但是非常重要的是您的“查询”实际上解决了 first 属性选择索引的顺序。
这在复合索引手册中的Prefixes 中有介绍。摘录:
"item": 1, "location": 1, "stock": 1
索引具有以下索引前缀:
项目:1 项目:1,位置:1对于复合索引,MongoDB 可以使用索引来支持对索引前缀的查询。因此,MongoDB 可以使用索引来查询以下字段:
项目字段, 项目字段和位置字段, item 字段和 location 字段和 stock 字段。但是,MongoDB 不能使用索引来支持包含以下字段的查询,因为没有 item 字段,列出的字段都不对应前缀索引:
位置字段, 库存字段,或 位置和库存字段。
因为您的查询引用了"loc"
first 并且不包括"category"
,所以没有选择索引并且MongoDB 返回错误。
所以为了使用您定义的索引,您还需要实际查询"category"
。修改您的列表:
var mongoose = require("mongoose");
mongoose.set('debug',true);
var LocationSchema = new mongoose.Schema(
userName: String,
category: Number,
loc:
'type': type: String, enum: "Point", default: "Point" ,
coordinates: type: [Number]
)
//LocationSchema.index( loc: "2dsphere", category: 1 , "background": false );
LocationSchema.index( category: 1, loc: "2dsphere" );
var Location = mongoose.model("location", LocationSchema);
var mongoDB = 'mongodb://localhost/test';
mongoose.Promise = global.Promise;
mongoose.connect(mongoDB, useMongoClient: true );
var testUser = Location(
userName: "Tester",
category: 1,
loc: coordinates: [12.44, 55.69]
);
testUser.save(function (err)
if (err)
return console.log("UPPPPs: " + err);
console.log("User Saved, Try to find him:");
let query = Location.find(
category: 1,
loc:
$near:
$geometry:
type: "Point",
coordinates: [12.50, 55.71]
,
$maxDistance: 600000
)
query.exec(function (err, docs)
if (err)
return console.log("Err: " + err);
console.log("Found: " + JSON.stringify(docs))
)
);
只要我们包含"category"
一切都很好:
用户已保存,请尝试找到他: Mongoose:locations.find( loc: '$near': '$geometry': type: 'Point', 坐标: [ 12.5, 55.71 ] , '$maxDistance': 600000 , 类别: 1 , 字段: ) 找到:["_id":"59f8f87554900a4e555d4e22","userName":"Tester","category":1,"__v":0,"loc":"coordinates":[12.44,55.69],"type" :"Point","_id":"59f8fabf50fcf54fc3dd01f6","userName":"Tester","category":1,"__v":0,"loc":"coordinates":[12.44,55.69] ,"type":"Point"]
另一种情况是简单地“前缀”带有位置的索引。确保首先删除以前的索引或集合:
LocationSchema.index( loc: "2dsphere", category: 1 , "background": false );
您可能应该养成设置"background": true
的习惯,否则在单元测试代码尝试使用索引之前,您开始在单元测试中遇到竞争条件。
【讨论】:
【参考方案2】:我对这个问题的第一个解决方案是通过 mLab 网络界面创建索引,这就像一个魅力。
我尝试了 Neil 建议的解决方案,但仍然失败。然而,Neil 给出的与索引相关的详细说明确实为我指明了问题的解决方案。 这是与我的测试代码执行以下操作相关的时间问题(如果您在本地运行数据库,您不会总是看到): 创建了索引,创建了一个 Location 文档(第一次也会创建集合),然后在 save 提供的回调中,我试图找到用户。似乎此处尚未创建索引,这就是导致错误的原因。
如果我将 find 方法延迟一秒,使用 setTimeout 可以正常工作。
不过,感谢 Neil 提供了有关正确使用索引的宝贵信息(背景):-)
【讨论】:
抱歉,您完全错了。正如我所提到的,您确实应该注意创建索引的时间,但正如我通过可重现的清单所证明的那样,index order 这就是您收到错误的原因。如果该索引的 "prefix" 未包含在查询中,则 MongoDB 无法选择正确的索引。这就是给出的答案所说的,因为那是您的代码中的问题。您没有包含"category"
,它是查询中索引的前缀。使用前缀为 "location"
或实际上包含其他前缀的索引才是真正解决的问题。以上是关于查询抱怨缺少 2dsphere-index,但它就在那里的主要内容,如果未能解决你的问题,请参考以下文章