I am trying to save a geojson, using mongoose and nodejs, for the moment I want to save a geojson of type 'MultiPoint'
this is the scheme that I have defined to save the geojson
let capaSchema = new Schema({
nombrecapa: {
type: String,
required: [true, 'El nombre de la capa es necesario']
},
descripcion: {
type: String,
required: [false]
},
geojson: Object([
geoSchema
])
});
const geoSchema = new Schema({
type: {
type: String,
default: 'FeatureCollection',
},
features: [
Object({
type: {
type: String,
default: 'Feature',
},
geometry: {
type: {
type: String,
default: 'MultiPoint'
},
coordinates: {
type: [
Number
],
index: '2dsphere'
}
}
})
],
});
this is the object that I want to save using the save method of moongose, first I make an instance of the schema, maybe my error may be inside the instance.
let capa = new Capa({
nombrecapa: body.nombrecapa,
descripcion: body.descripcion,
geojson: {
type: body.typefeature,
features: [{
type: body.featurestype,
geometry: {
type: body.geometrytype,
coordinates: [
[-105.01621, 39.57422],
[-105.01231, 39.57321]
]
}
}
]
}
});
capa.save((err, capadb) => {
if (err) {
return res.status(400).json({
ok: false,
err
})
}
res.json({
ok: true,
capa: capadb
})
})
but at the time of saving I returned the following errors:
"_message": "Capa validation failed",
"message": "Capa validation failed: geojson.0.features.0.geometry.coordinates: Cast to Array failed for value \"[ [ -105.01621, 39.57422 ], [ -105.01231, 39.57321 ] ]\" at path \"geometry.coordinates\"",
"name": "ValidationError"
In your schema you have coordinates as a single array but the data being passed is actually an array of nested arrays
I think what you need here is
coordinates: {
type: [[Number]],
index: '2dsphere'
}
Related
I am sending the object to create a user model.
"{
type: 'Point',
coordinates: [ 25.2239771, 51.4993224 ]
}"
And, here is the Mongoose Schema that I created.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserProfileSchema = new Schema(
{
userId: {
type: String,
// required: true,
unique: true,
},
userFirstName: {
type: String,
// required: true,
},
userLastName: {
type: String,
// required: true,
},
userGender: {
type: String,
// required: true,
},
userCoordinates: {
type: {
type: String,
default: 'Point',
},
coordinates: {
type: [Number],
index: '2dsphere',
},
},
},
{ collection: 'userprofilemodels' }
);
module.exports = UserProfile = mongoose.model(
'userprofilemodels',
UserProfileSchema
);
This is the code that I am using to add geoJson type file. However, I am getting an error.
I also tried to add index after the Schema has been defined
await new userProfileModel({
userId,
userFirstName,
userLastName,
userCoordinates,
})
.save()
.then(() => {
console.log('it worked!');
res.send('worked!');
})
.catch((error) => {
console.log('did not worl')
// console.log(error);
});
If I exclude userCoordinates, then it works. So, def my geoJson object is wrong. However, I have no clue where I have made mistakes.
Mongoose supports GeoJSON objects indexing so first add the "2dsphere" index to the userCoordintes rather than to the coordinates within the object in order to make it work.
userCoordinates: {
type: {
type: String,
default: 'Point',
},
coordinates: {
type: [Number],
default: undefined,
required: true
},
index: '2dsphere'
},
Make sure your userCoordinates looks something like this:
const userCoordinates = {
type: "Point",
coordinates: [coordinatesA, coordinatesB],
};
Taken from the mongoose documentation it seems the GeoJSON Type mustn't be only a String.
here is the example with location as a GeoJSON type:
const citySchema = new mongoose.Schema({
name: String,
location: {
type: {
type: String, // Don't do `{ location: { type: String } }`
enum: ['Point'], // 'location.type' must be 'Point'
required: true
},
coordinates: {
type: [Number],
required: true
}
}
});
I was trying to get random 20 foods near the particular location. When i used find it works but how to use aggregate with $near
Schema:
const foodSchema = new Schema({
foodName: {
type: String,
required: true
},
image: {
type: String,
required: true
},
price: {
type: String,
required: true
},
shopName: {
type: String,
required: true
},
isVerified:{
type:Boolean,
default:false,
required:true
},
isEnabled:{
type:Boolean,
default:false,
required:true
}
,
location: {
type: { type: String },
coordinates: [],
},
shopId:{
type: Schema.Types.ObjectId,
ref: 'Shop',
required: true
}
});
foodSchema.index({ location: "2dsphere" });
Food.aggregate([{$match:{isEnabled:true,location: {
$near: {
$maxDistance: 10000,
$geometry: {
type: "Point",
coordinates: [13.3339, 80.1943]
}
}
}}}])
.then(data=>{
console.log(data);
res.render('user/home',{
pageTitle:"UiMart",
foodlist:data
});
})
.catch(err=>{
console.log(err);
res.send("err");
});
MongoError: $geoNear, $near, and $nearSphere are not allowed in this context
How to use aggregate function with $near mongoose to get random foods near the particular location
Could you try something like this:
Food.aggregate
([
{
$geoNear: {
near: { type: "Point", coordinates: [13.3339, 80.1943] },
distanceField: "dist.calculated",
maxDistance: 10000,
query: { "isEnabled": true }
}
}
])
In the aggregation framework the $geoNear should be the first in the pipeline and you can use the query to filter the results instead of using match.
I am trying to use Mongo's GeoSpatial features to locate documents based on coordinates.
I need to create indexes for it to work - but it seems like I can't get the index created? Can you help?
I'll walk through what I have so far.
//User saves the location using a PUT Command.
props.updateBandLocation({
geometry: {
type: "Point",
coordinates: [ lat, lon ]
}
})
Here is the route that puts it in the database. I try to get the index created here.
router.put('/:id', (req, res) => {
quoteGenerator.findByIdAndUpdate({_id: req.params.id}, req.body).then(() => {
quoteGenerator.findOne({_id: req.params.id}).then(generator => res.send(generator))
quoteGenerator.createIndex( { bandLocation: "2dsphere" } )
})
})
The indexing throws an error in my terminal but it creates the location anyways. Here it is in the database.
//How the query looks in the database
"bandLocation": {
"geometry": {
"type": "Point",
"coordinates": [
32.96179,
-96.82916850000001
]
}
},
Lastly, I am trying to get all the documents near a point using this route.
router.get('/allbands/:lat/:lng', (req, res) => {
quoteGenerator.find(
{
bandLocation:
{ $near: {
$geometry: {
type : "Point",
coordinates : [-req.params.lng, +req.params.lat],
}
}
}
}
).then(bands => res.json(bands))
});
Thanks for any help you have to offer!
Here is my schema --
//Create GeoSchema
const GeoSchema = new Schema({
geometry: {
type: {
type: String,
default: "Point",
index: "2dsphere",
},
coordinates: {
type: [Number],
},
}
})
//Create Schema - Band
const AutoQuoteGeneratorSchema = new Schema({
baseCost: {
type: Number
},
mainDate: {
type: Object
},
quoteGenerator: {
type: Array,
required: true,
},
userId: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
bandName: {
type: String,
required: true,
},
bandBio: {
type: String,
required: true,
},
bandLocation: GeoSchema,
bandTour: {
type: Array,
required: true,
},
bandGenre: {
type: String,
required: true,
},
youtube: {
type: Array,
required: true,
},
published: {
type: Boolean,
required: true,
},
posts: {
type: Array,
required: true,
},
});
Ok so from what i can see we have a couple of problems:
Structure:
From the 2dsphere index docs:
The 2dsphere index supports data stored as GeoJSON objects and legacy coordinate pairs
What type are GeoJSON objects?, they're { type: <GeoJSON type> , coordinates: <coordinates> }
And what type are legacy coordinates pairs? they're in the form of: [<longitude>, <latitude> ] or { <field1>: <x>, <field2>: <y> }
So we can see bandLocation is neither, you need to use
quoteGenerator.createIndex( { "bandLocation.geometry": "2dsphere" } )
Your Coordinates are in the wrong order, You need to specify in the order of longitude then latitude. The valid range of latitude in degrees is -90 and +90. Your value of latitude of -96 is out of range.
So change your document to [-96.82916850000001, 32.96179].
Now we just need to adjust your query:
quoteGenerator.find({
"bandLocation.geometry":
{ $near: {
$geometry: {
type : "Point",
coordinates : [-req.params.lng, +req.params.lat],
}
}
}
})
** Another thing that pops up is that you create (try to create) an index every time there's a function call when in-fact you should only do it once. it should not be a part of your code. Now this won't throw an error but it's redundant as Mongo auto index documents on changes / inserts.
I am using comment array in my schema as fallows. I want to push comments data into that comment array using nodejs api
var Schema = mongoose.Schema;
var myfeeds = new Schema({
title: {
type: String,
required: true
},
feed: {
type: String,
required: true
},
createdBy: {
type: String,
required: true,
unique: true
},
createdDate: {
type: Date,
required: true,
default: Date.now()
},
comment: [
{
commentBy: {
type: String
},
commentText: {
type: String
},
createdDate: {
type: Date
}
}
],
likes: [
{
likesCount: {
type: Number,
required: false
},
likeBy: {
type: String,
required: false
}
}
]
});
I want to push object to this comment array. so, for that I did in this way please tell me if anything wrong in this
let _id = req.body.id;
let commentBy = req.body.commentedBy;
let commentedText = req.body.commentedText;
let commentedDate = req.body.commentedDate;
let data = {
commentBy: commentBy,
commentText: commentedText,
createdDate: commentedDate
};
MyFeeds.findByIdAndUpdate(
{ _id: _id },
{
$push: {
comment: data
}
}
)
.then((result) => {
res.status(200).json({
status: result
});
})
.catch((err) => {
res.status(500).json({
status: 'invalid',
err: err
});
});
but only id are inserted into that comment array but not the required content
"comment": [
{
"_id": "5badfd092b73fa14f4f0aa7c"
},
{
"_id": "5badfd102b73fa14f4f0aa7d"
},
{
"_id": "5badfd142b73fa14f4f0aa7e"
},
{
"_id": "5badfd31500fb11bb06b4c8a"
},
{
"_id": "5badfd35500fb11bb06b4c8b"
},
{
"_id": "5badff3d439a151190d62961"
}
],
My schema looks something like this for mongoose:
var LocationSchema = new Schema({
id: ObjectId,
geo: {
type: {
type: String,
required: true,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
},
coordinates: [{
type: Number,
es_lat_lon: true,
es_type: 'geo_point'
}]
}
});
Then I add mongoosastic plugin to mongoose initiate the model and create the mappings for mongoosastic
var esClient = new elasticsearch.Client({
host: config.es_url,
requestTimeout: Infinity,
keepAlive: true
});
LocationSchema.plugin(mongoosastic, { esClient: esClient })
var Location = mongoose.model('Location', LocationSchema);
/**
* mongoosastic create mappings
*/
Location.createMapping(function(err, mapping) {
if (err) {
console.log('error creating mapping (you can safely ignore this)');
console.log(err);
} else {
console.log('mapping created!');
console.log(mapping);
}
});
Now I get this error [Error: MapperParsingException[No handler for type [{default=Point, enum=[Point, LineString, Polygon], required=true, type=string}] declared on field [geo]]]
The full error in the log:
{
[Error: MapperParsingException[No handler for type [{default=Point, enum=[Point, LineString, Polygon], required=true, type=string}] declared on field [geo]]]
status: '400',
displayName: 'BadRequest',
message: 'MapperParsingException[No handler for type [{default=Point, enum=[Point, LineString, Polygon], required=true, type=string}] declared on field [geo]]'
}
My question is am I doing this completely wrong or am I just missing something small? The way I am doing this works for mongoose, only mongoosastic is having trouble and I understand why, but I can't be the first to run into this (reason why mongoosastic is having trouble is it sees type and does not expect it to have a type - at least that is what I think it is having trouble with).
Instead of
coordinates: [{
type: Number,
es_lat_lon: true,
es_type: 'geo_point'
}]
Try
coordinates: {
type: [Number],
es_type: 'geo_point'
}
EDIT:
OP Posted this solution.
Changed:
geo: {
type: {
type: String, ......
},
coordinates: [
{ type: Number, ..... }
]
}
To
geo: {
point_type: {
type: String, ......
},
coordinates: [
{ type: Number, ..... }
]
}