Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 查询抱怨缺少2dsphere索引,但它';在那里_Node.js_Mongodb_Mongoose_Mongodb Query_Geospatial - Fatal编程技术网

Node.js 查询抱怨缺少2dsphere索引,但它';在那里

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”索引确实是复合索引中的“第一

当我执行以下代码时(一个更大的示例,归结为要点)

我得到这个错误:

错误:MongoError:错误处理查询:ns=locationdemo.locationsTree:GEONEAR field=loc maxdist=600000 isNearSphere=0 排序:{} 项目:{} planner返回错误:找不到$geoNear查询的索引

但是索引在那里(见第10行)和下面mlab的截图。我做错了什么

你打破了一条关于如何使用索引的规则。虽然“2dsphere”索引确实是复合索引中的“第一”属性,但非常重要的是,为了选择索引,“查询”实际处理第一属性

这在关于复合索引的手册中有介绍。摘录:

{“项目”:1,“地点”:1,“库存”:1}

索引具有以下索引前缀:

  • {项目:1}
  • {项目:1,位置:1}
对于复合索引,MongoDB可以使用该索引来支持对索引前缀的查询。因此,MongoDB可以使用索引查询以下字段:

  • 项目字段
  • 项目字段和位置字段
  • 项目字段、位置字段和库存字段
但是,MongoDB无法使用索引来支持包含以下字段的查询,因为如果没有item字段,列出的字段中没有一个对应于前缀索引:

  • 位置字段
  • 股票市场,或
  • “位置”和“库存”字段
由于您的查询首先引用了
“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 });