Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one represent MongoDB GeoJSON fields in a Mongoose Schema?

MongoDB 2.4 allows the use of GeoJSON objects and a slew of neat functions and indexes that I'd like to use.

It expects GeoJSON objects to be stored in the format like:

loc: {
  type: 'Polygon',
  coordinates: [[[-180.0, 10.0], [20.0, 90.0], [180.0, -5.0], [-30.0, -90.0]]]
}

So in Mongoose one would think the schema would be defined like:

loc: { type: 'string', coordinates: [[['number']]] }

But this present two problems:

  1. having a field called "type" screws up Mongoose's schema parsing because it allows defining fields in the form field: { type: , index: } etc.

  2. Mongoose does not like nested arrays.

One way to overcome this is to simply use mongoose.Schema.Types.Mixed, however I feel that there has got to be a better way!

like image 792
Aaron Silverman Avatar asked Mar 21 '13 19:03

Aaron Silverman


People also ask

Does MongoDB support GeoJSON?

MongoDB supports the GeoJSON object types listed on this page. a field named coordinates that specifies the object's coordinates. If specifying latitude and longitude coordinates, list the longitude first, and then latitude. Valid longitude values are between -180 and 180 , both inclusive.

What does the schema in Mongoose define in MongoDB?

A Mongoose schema defines the structure of the document, default values, validators, etc., whereas a Mongoose model provides an interface to the database for creating, querying, updating, deleting records, etc.

What are schema methods in Mongoose?

Schemas not only define the structure of your document and casting of properties, they also define document instance methods, static Model methods, compound indexes, and document lifecycle hooks called middleware.

What is the preferred format to store geospatial data in MongoDB?

In MongoDB, you can store geospatial data as GeoJSON objects or as legacy coordinate pairs.


5 Answers

For reference, GeoJSON is officially supported in Mongoose 3.6

See the release notes here.

Example (from the docs):

new Schema({ loc: { type: [Number], index: '2dsphere'}})

... then ...

var geojsonPoly = { type: 'Polygon', coordinates: [[[-5,-5], ['-5',5], [5,5], [5,-5],[-5,'-5']]] }

Model.find({ loc: { $within: { $geometry: geojsonPoly }}})
// or
Model.where('loc').within.geometry(geojsonPoly)
like image 52
Jed Watson Avatar answered Oct 05 '22 09:10

Jed Watson


You must used Mixed to represent arrays of arrays. There is an open ticket to support this in the future.

@nevi_me is correct, you must declare the type property as he described.

Here's a gist: https://gist.github.com/aheckmann/5241574

See the mongoose tests here for more ideas: https://github.com/LearnBoost/mongoose/blob/master/test/model.querying.test.js#L1931

like image 45
aaronheckmann Avatar answered Oct 05 '22 09:10

aaronheckmann


The mongoose-geojson-schema package was created to make it easy to have GeoJSON in Mongoose Schemas.

like image 38
Mark Stosberg Avatar answered Oct 05 '22 10:10

Mark Stosberg


Mongoose now officially supports this.

In a nutshell, what you do is, for that schema, you use the typeKey setting to tell mongoose to use a different key for type information. Here is an example:

var schema = new Schema({
  // Mongoose interpets this as 'loc is an object with 2 keys, type and coordinates'
  loc: { type: String, coordinates: [Number] },
  // Mongoose interprets this as 'name is a String'
  name: { $type: String }
}, { typeKey: '$type' }); // A '$type' key means this object is a type declaration

So now instead of declaring type info with the type property, you use $type. This works at the schema level so use it in the schemas that need it.

like image 30
arg20 Avatar answered Oct 05 '22 10:10

arg20


I'm about to start moving all my location references in my MongoDB from '2d' to GeoJSON, so I'll encounter the same problem.

  • Regarding the type problem, you have to follow what I did below to get it working. Mongoose correctly recognises it as a string.
  • Nested arrays; I agree that mongoose.Schema.Types.Mixed will work, but I think you can try what I did below, let me know if it works. I'm not near a PC with mongo installed to try the schema out.

Here's how I'd define the schema. The nested array can be tweaked to work, so let me know if it doesn't.

var LocationObject = new Schema ({
  'type': {
    type: String,
    required: true,
    enum: ['Point', 'LineString', 'Polygon'],
    default: 'Point'
  },
  coordinates: [
    [
      { type: [ Number ]
    ]
  ]
});

If you get undesired results in the nesting of the Array, try this out instead. Basically nesting in deeper.

coordinates: [
  { type: [
    { type: [ Number ] }
  ] }
]
like image 30
nevi_me Avatar answered Oct 05 '22 09:10

nevi_me