danielemm
danielemm

Reputation: 1696

Mongoose/MongoDB Polygon data type and validation error

I would to store a polygon inside a MongoDB document using mongoose. This is my schema:

var alarmSchema = new mongoose.Schema({
    // ... some other fields ....
    loc :   {
        "type": {
            "type": String,
            "enum": [
                "Point",
                "MultiPoint",
                "LineString",
                "MultiLineString",
                "Polygon",
                "MultiPolygon"
            ]
        },
        "coordinates": [[Number]]
    }
});

So I've tried to add a new object of this type using:

var Alarm = db.model('Alarm', alarmSchema);
var alarmObj = new Alarm();
var polygonArray = [[10.371094,42.391009],[14.238281,44.024422],[16.259766,42.130821]];
alarmObj.loc = {type : "Polygon" , coordinates : polygonArray};
return alarmObj;

When i try to save this I get this error:

ValidationError: CastError: Cast to Array failed for value ....(the array passed)...

Any idea?

After that I would to find a list of these alarmObj which contains a passed point. I think this is the right query:

var geojsonPoint = { type: 'Point', coordinates: [44.95899,8.911711] }
AlarmModel.find({loc: { $geoIntersects: { $geometry: geojsonPoint}}},function(err,list) {});

Is it okay?

Upvotes: 1

Views: 3455

Answers (2)

westandy
westandy

Reputation: 1440

I built this "Location Schema" and it seems to handle Points and Polygons:

var locationSchema = new Schema({
    type: { 
            type: String, 
            enum: ['Point',
                   'MultiPoint',
                   'LineString',
                   'MultiLineString',
                   'Polygon',
                   'MultiPolygon'
            ],
            default: 'Point'
    },
    coordinates: { 
            // Array of {lat,lng} objects
            type: [{lat:{type:Number,max:90.0,min:-90.0},
                    lng:{type:Number,max:180.0,min:-180.0},
                    _id:false
            }],   
            default: [{lat:0,lng:0}] // Lat Lon
    }
},{_id:false});

var LocationModel = mongoose.model('Location',locationSchema);

// Test and validate polygon
var polygon = new LocationModel({
            type:'Polygon',
            coordinates:[{lat:-34.0,lng:105},{lat:-34.0,lng:106},
                         {lat:-35.0,lng:106},{lat:-35.0,lng:105}]
    });

polygon.validate(function(err){
    console.log(String(err));
});

// Test and validate point
var point = new LocationModel({
            type:'Point',
            coordinates:[{lat:-34.0,lng:105}]
    });

point.validate(function(err){
    console.log(String(err));
});

Hope this helps somebody.

EDIT:

After some work, for us, we ended up simplifying the 'Location' schema:

'use strict';

...

var schema = new Schema({
    type: {  // Type of Location
        type: String, 
        required: true,
        enum: ['Point','Polygon']
    },
    coordinates: { // Specified coordinates of location
        type: [],
        required: true
    }
},{_id:false});

... validation methods, etc.

let model = mongoose.model('Location',schema);

module.exports = {
    model : model,
    schema : schema
}

Model that uses the Location Model/Schema:

const Location = require('./Location');
const LocationSchema = Location.schema;

...

const schema = new Schema({
    ...
    location: {
        type: LocationSchema,
        required: true,
        validate: [Location.someValidationMethod, 'Specified location is not a point']},
    footprint: {
        type: LocationSchema,
        required: true,
        validate: [Location.someValidationMethod, 'Specified location is not        a Polygon']},
    ...
});

schema.index({'location','2dsphere'});
schema.index({'footprint','2dsphere'});

Test Driver:

let entry = new BlahModel({
    ...
    location:{
        type:'Point',
        coordinates:[0,2] // Lon/Lat
    },
    footprint:{
        type:'Polygon',
        coordinates:[[[0,10],[0,20],[10,20],[0,10]]]
    },
    ...

Upvotes: 3

dewhacker
dewhacker

Reputation: 71

Mongoose doesn't like the double array short hand [[Number]] https://github.com/Automattic/mongoose/issues/1361

You'll want to define your geojson schema generically if you're trying to handle all those types, for example Points are just 1D arrays, LineStrings are 2D, and Polygons are 3D. Give this a shot:

geo: {
    type: { type: String, "enum": [
            "Point",
            "MultiPoint",
            "LineString",
            "MultiLineString",
            "Polygon",
            "MultiPolygon"
        ] },
    coordinates:     { type: Array }
}

You can also check out some of these examples to help you get going: https://github.com/samluescher/geogoose https://github.com/rideamigoscorp/mongoose-geojson-schema

Hope this helps!

Upvotes: 1

Related Questions