Node.js 查询抱怨缺少2dsphere索引,但它';在那里
当我执行以下代码时(一个更大的示例,归结为要点) 我得到这个错误: 错误:MongoError:错误处理查询:ns=locationdemo.locationsTree:GEONEAR field=loc maxdist=600000 isNearSphere=0 排序:{} 项目:{} planner返回错误:找不到$geoNear查询的索引 但是索引在那里(见第10行)和下面mlab的截图。我做错了什么Node.js 查询抱怨缺少2dsphere索引,但它';在那里,node.js,mongodb,mongoose,mongodb-query,geospatial,Node.js,Mongodb,Mongoose,Mongodb Query,Geospatial,当我执行以下代码时(一个更大的示例,归结为要点) 我得到这个错误: 错误:MongoError:错误处理查询:ns=locationdemo.locationsTree:GEONEAR field=loc maxdist=600000 isNearSphere=0 排序:{} 项目:{} planner返回错误:找不到$geoNear查询的索引 但是索引在那里(见第10行)和下面mlab的截图。我做错了什么 你打破了一条关于如何使用索引的规则。虽然“2dsphere”索引确实是复合索引中的“第一
你打破了一条关于如何使用索引的规则。虽然“2dsphere”索引确实是复合索引中的“第一”属性,但非常重要的是,为了选择索引,“查询”实际处理第一属性 这在关于复合索引的手册中有介绍。摘录:
{“项目”:1,“地点”:1,“库存”:1}
索引具有以下索引前缀:
- {项目:1}
- {项目:1,位置:1}
- 项目字段
- 项目字段和位置字段
- 项目字段、位置字段和库存字段
- 位置字段
- 股票市场,或
- “位置”和“库存”字段
“loc”
,并且不包括“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))
})
});
只要我们包括“类别”
一切都很好:
用户已保存,请尝试查找他:Mongoose:locations.find({loc:{'$near':{'$geometry':{type:'Point',坐标:[12.5,55.71]},$maxDistance:'600000},类别:1},{fields:{}})
发现:[{u id:“59f8f87554900a4e555d4e22”,“用户名:”“测试者”,“类别:”:1,“{u v”:0,“位置:{”坐标:[12.44,55.69],“类型:”:“点”},{u id:“59f8fabf50fcf54fc3dd01f6”,“用户名:”“测试者”,“类别:”,“类别:”,“位置:{”坐标:[12.44,55.69],“类型:”:“点”}] 另一种情况是简单地用位置作为索引的前缀。确保先删除以前的索引或集合:
LocationSchema.index({ loc: "2dsphere", category: 1 },{ "background": false });
您可能应该习惯于设置
“background”:true
,否则,您将在单元测试中遇到竞争条件,在单元测试代码尝试使用索引之前,尚未完成索引的创建。我对该问题的第一个解决方案是通过mLab web界面创建索引,该界面工作得很好
我试过尼尔提出的解决办法,但还是失败了。然而,Neil给出的与索引相关的详细说明确实为我指明了问题的解决方案。
这是一个与我的测试代码执行以下操作有关的计时问题(如果在本地运行数据库,则不一定总能看到此问题):
创建了索引,创建了一个位置文档(第一次也将创建集合),然后在save提供的回调中,我试图找到用户。这里似乎还没有创建索引,这就是产生错误的原因
如果我将find方法延迟一秒钟,使用setTimeout它就可以正常工作
但是,感谢Neil提供了关于正确使用索引方法的宝贵信息(背景):-)在提供的答案中,您认为有什么不能解决您的问题吗?如果是,请对答案进行评论,以澄清哪些问题需要解决,哪些问题尚未解决。如果它确实回答了你提出的问题,那么请注意你提出的问题,但你完全错了。正如我提到的,您确实应该知道索引创建的时间安排,但正如我用一个可复制的列表所演示的,您收到错误的原因是索引顺序。如果查询中未包含索引的“前缀”,MongoDB将无法选择正确的索引。这就是给出的答案,因为这是代码中的问题。您没有在查询中包含作为索引前缀的
“category”
。实际解决的问题是使用前缀为“location”
的索引或实际包含另一个前缀。
LocationSchema.index({ loc: "2dsphere", category: 1 },{ "background": false });