AndreaM16 AndreaM16 - 3 months ago 18
Node.js Question

Unable to store LineStrings and Polygons - MEAN + Mongoose

I'm facing an issue that I was not able to solve looking at other Q/As on SO.

I'm building a web application that uses Google Maps Api as an interface to a MEAN Stack Application. I'm also using Mongoose to create my MongoDB Schema.


Unluckily, I'm not able to store LineStrings and Polygons. I'm only able to store Points and query them as I want (e.g. find closest points to another one).


When I try to POST a LineString or a Polygon I get the following error:

geoObjects validation failed
Cast to Array failed for value \"coordinates\" at path \"coordinates\"


Here's a Gist with the full Postman Log.

Here's my Schema:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var geoObjects = new Schema({
name : {type: String},
type: {
type: String,
enum: [
"Point",
"LineString",
"Polygon"
],
default : 'Point'
},
coordinates: [Number],
});

geoObjects.index({coordinates: '2dsphere'});
module.exports = mongoose.model('geoObjects', geoObjects);


This is my Post Route:

var mongoose = require('mongoose');
var GeoObjects = require('./model.js');

app.post('/geoObjects', function(req, res) {

// Creates a new Point based on the Mongoose schema and the post body
var newObj = new GeoObjects(req.body);

// New Points is saved in the db.
newObj.save(function(err) {
if (err){
res.send(err);
return;
}

// If no errors are found, it responds with a JSON of the new point
res.json(req.body);
});
});


And these are two examples of LineString and Polygons that I'm trying to POST:

{
"name":"myPolygon",
"type": "Polygon",
"coordinates": [
[ [25.774, -80.190], [18.466, -66.118],
[32.321, -64.757], [25.774, -80.190]
]
]
}

{
"name":"myLineString",
"type": "LineString",
"coordinates": [
[17.811, 12.634], [12.039, 18.962],
[15.039, 18.962], [27.039, 18.962]
]
}



In a previous version, I had
coordinates: [Schema.Types.Mixed]
that
allowed me to store all the 3 kind of geoObjects, but, unluckily, I
was forced to switch to a different schema since with
Schema.Types.Mixed
it was not possible to let my queries work on
points.



  1. Why Am I not able to POST LineStrings and Polygons?

  2. How Can I solve this issue?



Thanks in advance, if you need any clarification on the problem just leave a comment.

Answer

I managed to solve this issue splitting the initial schema in 3 different schemas, one per each type.

Here are correct schemas which allow using geoQueries and storing geoObjects

marker-model.js

// Pulls Mongoose dependency for creating schemas
var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

var markers = new Schema({
    name : {type: String},
    type: {
        type: String,
        default : 'Point'
    },
    coordinates: {type: [Number], index:true},
    created_at:  {type: Date, default: Date.now},
    updated_at:  {type: Date, default: Date.now}
});

// Sets the created_at parameter equal to the current time
markers.pre('save', function(next){
    now = new Date();
    this.updated_at = now;
    if(!this.created_at) {
        this.created_at = now
    }
    next();
});

// Indexes this schema in 2dsphere format 
markers.index({coordinates: '2dsphere'});
module.exports = mongoose.model('markers', markers);

linestring-model.js:

var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

// Creates a LineString Schema.
var linestrings = new Schema({
    name: {type: String, required : true},
    geo : {
        type : {type: String,
            default: "LineString"},
        coordinates : Array
    },
    created_at: {type: Date, default: Date.now},
    updated_at: {type: Date, default: Date.now}
});

// Sets the created_at parameter equal to the current time
linestrings.pre('save', function(next){
    now = new Date();
    this.updated_at = now;
    if(!this.created_at) {
        this.created_at = now
    }
    next();
});

linestrings.index({geo : '2dsphere'});
module.exports = mongoose.model('linestrings', linestrings);

polygon-model.js

var mongoose = require('mongoose');
var Schema   = mongoose.Schema;

// Creates a Polygon Schema.
var polygons = new Schema({
    name: {type: String, required : true},
    geo : {
        type : {type: String,
            default: "Polygon"},
        coordinates : Array
    },
    created_at: {type: Date, default: Date.now},
    updated_at: {type: Date, default: Date.now}
});

// Sets the created_at parameter equal to the current time
polygons.pre('save', function(next){
    now = new Date();
    this.updated_at = now;
    if(!this.created_at) {
        this.created_at = now
    }
    next();
});

polygons.index({geo : '2dsphere'});
module.exports = mongoose.model('polygons', polygons);

LineString Insert:

{  
    "name" : "myLinestring", 
    "geo" : {
        "type" : "LineString", 
        "coordinates" : [
            [
                17.811, 
                12.634
            ], 
            [
                12.039, 
                18.962
            ], 
            [
                15.039, 
                18.962
            ], 
            [
                29.039, 
                18.962
            ]
        ]
    }
}

Polygon Insert:

{  
    "name" : "Poly", 
    "geo" : {
        "type" : "Polygon", 
        "coordinates" :  [
                           [ 
                             [25.774, -80.190], [18.466, -66.118], 
                             [32.321, -64.757], [25.774, -80.190] 
                           ]
                         ]
    }
}

I hope it will help someone.