Skip to content

Instantly share code, notes, and snippets.

@PascalAnimateur
Last active February 22, 2021 20:19
Show Gist options
  • Save PascalAnimateur/b73617f0a27475fd4ccb to your computer and use it in GitHub Desktop.
Save PascalAnimateur/b73617f0a27475fd4ccb to your computer and use it in GitHub Desktop.
Geospatial example in Sails.js using native MongoDB query
module.exports.bootstrap = function(cb) {
// Ensure we have 2dsphere index on coordinates attribute of Place.
sails.models.place.native(function (err, collection) {
collection.ensureIndex({ coordinates: '2dsphere' }, function () {
// It's very important to trigger this callback method when you are finished
// with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap)
cb();
});
});
};
module.exports.models = {
// Geospatial queries require MongoDB connection (sails-mongo)
connection: 'someMongodbServer'
};
/* Place model */
module.exports = {
attributes: {
name: {
type: 'string',
required: true
},
// This is the attribute used for the place's geolocation.
// Be careful to store it as [ lng, lat ] or else geoNear queries will give imprecise results.
coordinates: {
type: 'json',
required: true
}
},
/**
* Find places closer than a certain distance (in km) from a specified location [ lng, lat ].
* @param conditions
* JSON object should look like this:
* {
* lng: -72.213,
* lat: 45.012,
* maxDistance: 100,
* limit: 20,
* }
*
* @param callback (err, results)
* Returns an array of results (ordered by increasing distance), it looks like this:
* [
* {
* dis: 10.321,
* obj: { JSON object of Place }
* },
* {
* dis: 20.123,
* obj: { JSON object of Place }
* }
* ]
*/
findNear: function (conditions, callback) {
Place.native(function (err, collection) {
if (err) return callback(err);
collection.geoNear({
type: "Point" ,
coordinates: [ conditions.lng, conditions.lat ]
}, {
limit: conditions.limit || 30,
maxDistance: conditions.maxDistance * 1000.0,
distanceMultiplier: 0.001,
spherical : true
}, function (err, places) {
if (err) return callback(err);
return callback(null, places.results);
});
});
}
};
/* Place controller */
module.exports = {
/**
* Create two dummy places.
*/
dummy: function (req, res) {
Place.create({
name: 'New Richmond',
coordinates: [ -65.8716805, 48.1804069 ]
}, function (err, place) {
if (err) return res.negotiate(err);
console.log('Place created: ', place);
res.ok();
});
Place.create({
name: 'Montreal',
coordinates: [ -73.5647636, 45.5158157 ]
}, function (err, place) {
if (err) return res.negotiate(err);
console.log('Place created: ', place);
res.ok();
});
},
/**
* Find places closer than a certain distance (in km) from a specified location [ lng, lat ].
*/
search: function (req, res) {
// TODO: Default values and conditions validation should go in Place.findNear
var conditions = {
lng: parseFloat(req.param('lng')) || 0,
lat: parseFloat(req.param('lat')) || 0,
maxDistance: parseFloat(req.param('maxDistance')) || 1000,
limit: req.param('limit') || 30,
};
Place.findNear(conditions, function (err, results) {
if (err) return res.negotiate(err);
return res.json(results);
});
}
};
@nanyaks
Copy link

nanyaks commented May 3, 2016

Thanks @PascalAnimateur. Works perfectly!

@shantanu2
Copy link

@PascalAnimateur

 module.exports.bootstrap = function(cb) {

  // Ensure we have 2dsphere index on coordinates attribute of Place.
  sails.models.modelName.native(function (err, collection) {
    collection.ensureIndex({ coordinates: '2dsphere' }, function () {

      // It's very important to trigger this callback method when you are finished
      // with the bootstrap!  (otherwise your server will never lift, since it's waiting on the bootstrap)
      cb();

    });
  });

};

its giving me error

error: Bootstrap encountered an error: (see below)
error: TypeError: Cannot read property 'native' of undefined
    at Object.module.exports.bootstrap (E:\codes\backend\Masterbackend\config\bootstrap.js:17:32)
    at Sails.runBootstrap (C:\Users\hp\AppData\Roaming\npm\node_modules\sails\lib\app\private\bootstrap.js:44:25)
    at Sails.wrapper [as runBootstrap] (C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\@sailshq\lodash\lib\index.js:3250:19)
    at Sails.initialize (C:\Users\hp\AppData\Roaming\npm\node_modules\sails\lib\app\private\initialize.js:68:9)
    at wrapper (C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\@sailshq\lodash\lib\index.js:3250:19)
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:713:13
    at iterate (C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:262:13)
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:274:29
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:44:16
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:718:17
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:167:37
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\lib\app\load.js:184:13
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:52:16
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:548:17
    at C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:542:17
    at _arrayEach (C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:85:13)
    at Immediate.taskComplete [as _onImmediate] (C:\Users\hp\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:541:13)
    at runCallback (timers.js:800:20)
    at tryOnImmediate (timers.js:762:5)
    at processImmediate [as _immediateCallback] (timers.js:733:5)

any help ????

@shantanu2
Copy link

Found Out Solution

module.exports.bootstrap = function(cb) {

  // Ensure we have 2dsphere index on coordinates attribute of Place.
  modelName.native(function (err, collection) {
    collection.ensureIndex({ coordinates: '2dsphere' }, function () {

      // It's very important to trigger this callback method when you are finished
      // with the bootstrap!  (otherwise your server will never lift, since it's waiting on the bootstrap)
      cb();

    });
  });

};

using native via modelName solve the problem

@tiham07
Copy link

tiham07 commented Dec 1, 2017

There are three main things to be considered:

  1. The 2dsphere index needs to be created properly (As described in the bootstrap.js.
  2. The name of the coordinates fields must be exactly coordinates (not coord, coordinate, position, ...)
  3. The positions need to be inserted with [longitude, latitude] not with [latitude, longitude].

@pb-z
Copy link

pb-z commented Aug 2, 2019

Thanks, this gist is really helpful!
Since .native() has been deprecated, the new bootstrap.js like below:

// Ensure we have 2dsphere index on coordinates attribute of Place.
  var db = Place.getDatastore().manager;
  var collection = db.collection('Place');
  collection.ensureIndex({ coordinates: '2dsphere' }, () => {

    // It's very important to trigger this callback method when you are finished
    // with the bootstrap!  (otherwise your server will never lift, since it's waiting on the bootstrap)
    cb();
  });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment