当前位置: 首页 > 知识库问答 >
问题:

查询抱怨缺少2dsphere索引,但它确实存在

钱华晖
2023-03-14

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

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 is近球体=0排序:{}Proj:{}planner返回错误:无法找到$Geo近查询的索引

共有2个答案

邴和雅
2023-03-14

我对这个问题的第一个解决方案是通过mLab web界面创建索引,该界面工作得非常出色。

我试过尼尔提出的解决办法,但还是失败了。然而,Neil给出的与索引相关的详细说明确实为我指明了问题的解决方案。这是一个与我的测试代码执行以下操作相关的时间问题(如果在本地运行数据库,您不会总是看到这个问题):创建索引,创建位置文档(第一次也将创建集合),然后在save提供的回调中,我尝试查找用户。这里似乎还没有创建索引,这就是产生错误的原因。

如果我将find方法延迟一秒钟,使用setTimeout它就可以正常工作。

但是,仍然感谢尼尔提供的关于使用索引的正确方式的有价值的信息(背景):-)

农飞尘
2023-03-14

你打破了一条关于如何使用索引的规则。虽然“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))
  })
});

只要我们包括“类别”一切都很好:

用户已保存,尝试找到他:
猫鼬:locations.find({loc:{'$近': { '$几何':{类型:'点',坐标:[12.5, 55.71 ] }, '$最大距离': 600000}},类别: 1},{字段: {} })
找到:[{"_id":"59f8f87554900a4e555d4e22","userName":"Tester","类别": 1,"__v": 0,"loc":{"坐标":[12.44,55.69],"type":"Point"}},{"_id":"59f8Fabf50fcf54fc3dd01f6","userName":"Tester","class": 1,"__v": 0,"loc":{"坐标":[12.44,55.69],"类型":"点"}}]

另一种情况是简单地用位置“前缀”索引。确保先删除以前的索引或集合:

LocationSchema.index({ loc: "2dsphere", category: 1 },{ "background": false });

您可能应该习惯于设置“background”:true,否则您将在单元测试中遇到竞争条件,在单元测试代码尝试使用索引之前,尚未完成索引的创建。

 类似资料:
  • 问题内容: 在Swift 1.2的最新升级之后,我不知道如何将一行文本拆分为单词。我曾经这样做: 但这不再起作用,因为… 嗯,好吧,即使我可以上次建造?好吧,让我们尝试… 好吧,我能想到的所有其他版本都说: 让我们来听听它对新编程语言进行Beta测试!好极了! 有人知道1.2的正确秘密调味料吗? 问题答案: 在Swift 1.2中,似乎参数的顺序已更改: 或者,使用默认值: 谓词现在是最后一个参数

  • 问题内容: 我正在尝试连接到远程主机,并检查文件是否存在。在此阶段,我仅尝试连接,但是出现错误: 我试图找出其他人是否有像我一样的问题,但我却找不到。 我知道我需要在此过程中以某种方式检查knowns_hosts,但我只是想不通如何… 问题答案: 您在这里寻找的是: 然后将您的hostKey定义行替换为 有关此主题的更多信息: 我从中获取部分代码的官方样本 为什么现在需要hostKey 编辑:还请

  • 问题内容: 当我这样做时(在laravel中): 它说: SQLSTATE [HY093]:无效的参数号(SQL:SELECT * FROM my_table,其中id =:id || id =:id) 但是当我这样做时(使用纯PHP): 成功了。我究竟做错了什么? PS显然,遇到问题时我运行的查询更有意义。 UPD 或多或少的真实查询: 问题答案: 从我所看到的一切都可以归结为无法处理命名参数。

  • 我很少使用HTML和JavaScript,几乎忘记了最基本的内容。错误是什么? DevTools未能加载SourceMap:无法加载的内容https://cdn.jsdelivr.net/npm/@tensorflow/tf。min.js。映射:HTTP错误:状态代码404,网络::错误\u HTTP\u响应\u代码\u失败

  • 我使用Gradle 6.3和Jacoco来编译、测试和显示覆盖率报告。但是我不明白为什么它抱怨“两个分支中的一个丢失了”,根本没有分支: 下面是完整的静态编程语言数据类: 如果幕后有树枝,它们是什么?我该如何覆盖它们?

  • 我正在编写一个应用程序来自动构建和运行SQL查询。对于许多表,我的代码工作正常,但在某个表上,它会抛出以下异常: 已运行的查询如下所示: 这实际上是从列中返回非空值。 我不明白为什么在pgAdmin 4中出现“列不存在”错误。我可以看到有一个名为的模式,其中包含表,该表有一个名为的列。 既然所有的列、模式和表名都是由应用程序本身检索的,我不认为存在拼写或语义错误,那么为什么PostgreSQL会导