$near error - planner returned error: unable to find index for $geoNear query

Gan*_*rey 2 geolocation mongoose mongodb geojson node.js

I am having great trouble with this. I am building a little API to get the closest stored elements (in a mlab MongoDB) given specific coordinates.

\n\n

I want to get the closest elements from my DB using Mongo custom query tools like $near.

\n\n

You can find the original repo here!

\n\n

The Data

\n\n

The original data is a little .csv that I converted to geojson format.

\n\n

Here is a short version of that .csv:

\n\n

一个包含事件坐标的小 csv

\n\n

Here is the geojson version of it:

\n\n
{\n  "type": "FeatureCollection",\n  "features": [\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.4049238868200975, 48.82094216189432]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.3645320381923534, 48.816341825787724]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.3274838513968072, 48.86982967859056]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.23284629237154, 48.89111120713999]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.23284629237154, 48.89111120713999]\n      },\n      "properties": {\n        "event_type": "click"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.4204737962258305, 48.85038737901075]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.4214870126092594, 48.86339618816508]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.4144620076022436, 48.876530301936576]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    },\n    {\n      "type": "Feature",\n      "geometry": {\n        "type": "Point",\n        "coordinates": [2.2470618097659285, 48.88845096504584]\n      },\n      "properties": {\n        "event_type": "imp"\n      }\n    }\n  ]\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

The Model

\n\n

Here is the schema using mongoose (as you can see, I did add 2dsphere index):

\n\n
const mongoose = require("mongoose");\n\nconst FeatureSchema = new mongoose.Schema({\n  type: String,\n  geometry: {\n    type: { type: String, default: "Point" },\n    coordinates: { type: [Number] }\n  },\n  properties: { event_type: String }\n});\n\nFeatureSchema.index({ geometry: "2dsphere" });\nconst MapEventSchema = new mongoose.Schema({\n  type: String,\n  features: [FeatureSchema]\n});\n\nconst MapEvent = mongoose.model("mapEvent", MapEventSchema);\n\nmodule.exports = MapEvent;\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

The Test

\n\n

Here is now the test (with Mocha) that I am struggling with:

\n\n
const assert = require("assert");\nconst MapEvent = require("../src/models/mapEvents");\nconst fs = require("fs");\n\ndescribe("Read test", () => {\n  // create new room collection because collection is drop between each file\n  beforeEach(done => {\n    rawJSON = fs.readFileSync("./src/assets/test_assets/read_test.json");\n    const parsedContent = JSON.parse(rawJSON);\n    const mapEvent = new MapEvent(parsedContent);\n    mapEvent\n      .save()\n      .then(() => {\n        done();\n      })\n      .catch(error => {\n        console.error(error);\n      });\n  });\n\n  it("Find nearest event by coordonates", done => {\n    const distance = 1000;\n    const lat = 48.86;\n    const lon = 2.35;\n\n    function waitForIndex() {\n      return new Promise((resolve, reject) => {\n        MapEvent.on("index", error => (error ? reject(error) : resolve()));\n      });\n    }\n\n    MapEvent.findOne({\n      geometry: {\n        $near: [lat, lon],\n        $maxDistance: distance\n      }\n    })\n      //.then(waitForIndex)\n      .then(MapEvent.init())\n      .then(nearestResult => {\n        console.log("------------");\n        console.log(nearestResult);\n        console.log("------E-----");\n        assert(nearestResult);\n        done();\n      })\n      .catch(error => {\n        console.error("************");\n        console.error(error);\n        console.error("******E*****");\n      });\n  });\n}); \n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

The Output

\n\n

As you may notice, I commented out waitForIndex() (find on a related Stackoverflow question) to use MapEvent.init() instead (find on github). Unfortunately, both solutions give me the same error output.

\n\n
Connection is established\n  Create test\n(node:12483) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.\n    \xe2\x9c\x93 MapEvent saving\n\n  Read test\n************\n{ MongoError: error processing query: ns=babylon_ad_db.mapevents batchSize=1 limit=1Tree: GEONEAR  field=geometry maxdist=1000 isNearSphere=0\nSort: {}\nProj: {}\n planner returned error: unable to find index for $geoNear query\n    at queryCallback (/home/geoffrey/babylon-ad/node_modules/mongodb-core/lib/cursor.js:248:25)\n    at /home/geoffrey/babylon-ad/node_modules/mongodb-core/lib/connection/pool.js:532:18\n    at process._tickCallback (internal/process/next_tick.js:61:11)\n  ok: 0,\n  errmsg:\n   \'error processing query: ns=babylon_ad_db.mapevents batchSize=1 limit=1Tree: GEONEAR  field=geometry maxdist=1000 isNearSphere=0\\nSort: {}\\nProj: {}\\n planner returned error: unable to find index for $geoNear query\',\n  code: 2,\n  codeName: \'BadValue\',\n  operationTime:\n   Timestamp { _bsontype: \'Timestamp\', low_: 7, high_: 1536667477 },\n  \'$clusterTime\':\n   { clusterTime:\n      Timestamp { _bsontype: \'Timestamp\', low_: 7, high_: 1536667477 },\n     signature: { hash: [Binary], keyId: [Long] } },\n  name: \'MongoError\',\n  [Symbol(mongoErrorContextSymbol)]: {} }\n******E*****\n    1) Find nearest event by coordonates\n\n\n  1 passing (3s)\n  1 failing\n\n  1) Read test\n       Find nearest event by coordonates:\n     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/geoffrey/babylon-ad/test/read_test.js)\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

我已经做了一些谷歌搜索,这就是我听说 $near 和 2dsphere 索引的方式。但我仍然不明白为什么它说找不到索引。即使我用 waitForIndex() 或 MapEvent.init() 等待它。

\n\n

这个社区创造了一些很酷的奇迹,我希望你能帮助我。

\n\n

谢谢,

\n

cyb*_*bat 5

此类错误表明索引未创建。通常这是由于坐标数据无效造成的。也许加载您的 mongo shell 并确保您的索引存在:

mongo
use yourdatabasename
db.yourcollection.getIndexes()
Run Code Online (Sandbox Code Playgroud)

你最终应该得到类似的结果:

{
    "v" : 2,
    "key" : {
      "geometry" : "2dsphere"
    },
    "name" : "geometry_2dsphere",
    "ns" : "databasename.yourcollection",
    "2dsphereIndexVersion" : 3
  }
Run Code Online (Sandbox Code Playgroud)

如果不存在,请尝试在 shell 中创建索引 - 如果无法创建索引,则会抛出错误:

db.yourcollection.createIndex( { geometry : "2dsphere" } )
Run Code Online (Sandbox Code Playgroud)

  • 可能有人创建了索引,但使用了错误的说明符,例如,在我的例子中,我为“坐标”而不是“位置”创建了“2dsphere”索引,该索引适用于某些查询,但不适用于“$geoNear” 。 (2认同)