Gane D. Geoffrey
Gane D. Geoffrey

Reputation: 185

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

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.

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

You can find the original repo here!

The Data

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

Here is a short version of that .csv:

A little csv containing events coordinates

Here is the geojson version of it:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.4049238868200975, 48.82094216189432]
      },
      "properties": {
        "event_type": "imp"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.3645320381923534, 48.816341825787724]
      },
      "properties": {
        "event_type": "imp"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.3274838513968072, 48.86982967859056]
      },
      "properties": {
        "event_type": "imp"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.23284629237154, 48.89111120713999]
      },
      "properties": {
        "event_type": "imp"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.23284629237154, 48.89111120713999]
      },
      "properties": {
        "event_type": "click"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.4204737962258305, 48.85038737901075]
      },
      "properties": {
        "event_type": "imp"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.4214870126092594, 48.86339618816508]
      },
      "properties": {
        "event_type": "imp"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.4144620076022436, 48.876530301936576]
      },
      "properties": {
        "event_type": "imp"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [2.2470618097659285, 48.88845096504584]
      },
      "properties": {
        "event_type": "imp"
      }
    }
  ]
}

The Model

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

const mongoose = require("mongoose");

const FeatureSchema = new mongoose.Schema({
  type: String,
  geometry: {
    type: { type: String, default: "Point" },
    coordinates: { type: [Number] }
  },
  properties: { event_type: String }
});

FeatureSchema.index({ geometry: "2dsphere" });
const MapEventSchema = new mongoose.Schema({
  type: String,
  features: [FeatureSchema]
});

const MapEvent = mongoose.model("mapEvent", MapEventSchema);

module.exports = MapEvent;

The Test

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

const assert = require("assert");
const MapEvent = require("../src/models/mapEvents");
const fs = require("fs");

describe("Read test", () => {
  // create new room collection because collection is drop between each file
  beforeEach(done => {
    rawJSON = fs.readFileSync("./src/assets/test_assets/read_test.json");
    const parsedContent = JSON.parse(rawJSON);
    const mapEvent = new MapEvent(parsedContent);
    mapEvent
      .save()
      .then(() => {
        done();
      })
      .catch(error => {
        console.error(error);
      });
  });

  it("Find nearest event by coordonates", done => {
    const distance = 1000;
    const lat = 48.86;
    const lon = 2.35;

    function waitForIndex() {
      return new Promise((resolve, reject) => {
        MapEvent.on("index", error => (error ? reject(error) : resolve()));
      });
    }

    MapEvent.findOne({
      geometry: {
        $near: [lat, lon],
        $maxDistance: distance
      }
    })
      //.then(waitForIndex)
      .then(MapEvent.init())
      .then(nearestResult => {
        console.log("------------");
        console.log(nearestResult);
        console.log("------E-----");
        assert(nearestResult);
        done();
      })
      .catch(error => {
        console.error("************");
        console.error(error);
        console.error("******E*****");
      });
  });
}); 

The Output

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.

Connection is established
  Create test
(node:12483) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
    ✓ MapEvent saving

  Read test
************
{ MongoError: error processing query: ns=babylon_ad_db.mapevents batchSize=1 limit=1Tree: GEONEAR  field=geometry maxdist=1000 isNearSphere=0
Sort: {}
Proj: {}
 planner returned error: unable to find index for $geoNear query
    at queryCallback (/home/geoffrey/babylon-ad/node_modules/mongodb-core/lib/cursor.js:248:25)
    at /home/geoffrey/babylon-ad/node_modules/mongodb-core/lib/connection/pool.js:532:18
    at process._tickCallback (internal/process/next_tick.js:61:11)
  ok: 0,
  errmsg:
   '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',
  code: 2,
  codeName: 'BadValue',
  operationTime:
   Timestamp { _bsontype: 'Timestamp', low_: 7, high_: 1536667477 },
  '$clusterTime':
   { clusterTime:
      Timestamp { _bsontype: 'Timestamp', low_: 7, high_: 1536667477 },
     signature: { hash: [Binary], keyId: [Long] } },
  name: 'MongoError',
  [Symbol(mongoErrorContextSymbol)]: {} }
******E*****
    1) Find nearest event by coordonates


  1 passing (3s)
  1 failing

  1) Read test
       Find nearest event by coordonates:
     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)

I already made some googling, this is how I heard about $near and 2dsphere index. But still, I can't figure out why it says that it can't find an index. Even when I wait for it with waitForIndex() or MapEvent.init().

This community did some cool miracles, I hope you will help me.

Thanks,

Upvotes: 2

Views: 8212

Answers (1)

cyberwombat
cyberwombat

Reputation: 40084

This type of error indicates the index was not created. Usually this is due to invalid coordinate data. Perhaps load up your mongo shell and ensure your indexes are present:

mongo
use yourdatabasename
db.yourcollection.getIndexes()

You should end up with something like:

{
    "v" : 2,
    "key" : {
      "geometry" : "2dsphere"
    },
    "name" : "geometry_2dsphere",
    "ns" : "databasename.yourcollection",
    "2dsphereIndexVersion" : 3
  }

if not present, try creating the index in the shell - it will throw errors if it cannot create one.:

db.yourcollection.createIndex( { geometry : "2dsphere" } )

Upvotes: 6

Related Questions