Reputation: 185
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 original data is a little .csv that I converted to geojson format.
Here is a short version of that .csv:
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"
}
}
]
}
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;
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*****");
});
});
});
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
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