Using GeoJSON

    GeoJSON is a format for storing geographic points and polygons. on GeoJSON objects. Let’s take a look at how you can use Mongoose to store and query GeoJSON objects.

    The most simple structure in GeoJSON is a point. Below is an example point representing the approximate location of San Francisco. Note that longitude comes first in a GeoJSON coordinate array, not latitude.

    Below is an example of a Mongoose schema where is a point.

    1. const citySchema = new mongoose.Schema({
    2. name: String,
    3. location: {
    4. type: {
    5. type: String, // Don't do `{ location: { type: String } }`
    6. enum: ['Point'], // 'location.type' must be 'Point'
    7. required: true
    8. },
    9. coordinates: {
    10. type: [Number],
    11. required: true
    12. }
    13. }
    14. });
    1. const pointSchema = new mongoose.Schema({
    2. type: {
    3. type: String,
    4. enum: ['Point'],
    5. required: true
    6. },
    7. coordinates: {
    8. type: [Number],
    9. required: true
    10. }
    11. });
    12. const citySchema = new mongoose.Schema({
    13. name: String,
    14. location: {
    15. type: pointSchema,
    16. }
    17. });

    GeoJSON polygons let you define an arbitrary shape on a map. For example, the below polygon is a GeoJSON rectangle that approximates the border of the state of Colorado.

    Polygons are tricky because they use triple nested arrays. Below is how you create a Mongoose schema where coordinates is a triple nested array of numbers.

    1. const polygonSchema = new mongoose.Schema({
    2. type: {
    3. type: String,
    4. enum: ['Polygon'],
    5. required: true
    6. },
    7. coordinates: {
    8. type: [[[Number]]], // Array of arrays of arrays of numbers
    9. required: true
    10. }
    11. });
    12. const citySchema = new mongoose.Schema({
    13. name: String,
    14. location: polygonSchema
    15. });

    Mongoose queries support the same that the MongoDB driver does. For example, the below script saves a city document those location property is a GeoJSON point representing the city of Denver, Colorado. It then queries for all documents within a polygon representing the state of Colorado using the MongoDB $geoWithin operator.

    1. const City = db.model('City', new Schema({
    2. name: String,
    3. location: pointSchema
    4. }));
    5. const colorado = {
    6. coordinates: [[
    7. [-109, 41],
    8. [-102, 37],
    9. [-109, 37],
    10. [-109, 41]
    11. ]]
    12. };
    13. const denver = { type: 'Point', coordinates: [-104.9903, 39.7392] };
    14. return City.create({ name: 'Denver', location: denver }).
    15. then(() => City.findOne({
    16. location: {
    17. $geoWithin: {
    18. $geometry: colorado
    19. }
    20. }
    21. })).
    22. then(doc => assert.equal(doc.name, 'Denver'));

    Mongoose also has a that’s a shorthand for $geoWithin.

    MongoDB supports 2dsphere indexes for speeding up geospatial queries. Here’s how you can define a 2dsphere index on a GeoJSON point:

    1. const denver = { type: 'Point', coordinates: [-104.9903, 39.7392] };
    2. const City = db.model('City', new Schema({
    3. name: String,
    4. location: {
    5. type: pointSchema,
    6. index: '2dsphere' // Create a special 2dsphere index on `City.location`
    7. }
    8. }));
    9. return City.create({ name: 'Denver', location: denver }).
    10. then(() => City.findOne().where('location').within(colorado)).

    You can also define a geospatial index using the as shown below.

    1. citySchema.index({ location: '2dsphere' });