Mongoose Geolocation set default coordinates - node.js

I am trying to create mongoose geolocation records with default coordinates. I am able to set the default values so it they are serialized, but they are not really committed to the database so geospatial queries won't work. Here is what I am doing (simplified)
const Place = new mongoose.Schema({
name: { type: String, required: true },
location: {
type: {
type: String,
enum: ['Point'],
required: true,
default: 'Point'
},
coordinates: {
type: [Number],
required: true,
default: function () {
return [0, 0] // Just 0, 0 for the example
}
}
}
When I pull up the record in the mongo shell, there is no location key at all.

i don't know more efficient way
but try this :
//pass data like this in your controller
Store.create({name, lat, lon})
make your model like this
const Place = new mongoose.Schema({
name: { type: String, required: true },
lat: { type: String},
lon: { type: String},
location: {
type: {
type: String,
enum: ['Point'],
},
coordinates: {
type: [Number],
index: '2dsphere'
}
}
// run before saving documents
Place.pre('save', function(next) {
this.location = {
type: 'Point',
coordinates: [this.lat, this.lon]
};
next();
});

Related

How to check already existing latitude and longitude in Mongo DB before adding?

I defined a schema like this to store locations. Now I want to add a location by checking lat and long.
export interface Location {
type: string;
coordinates: [number];
}
const pointSchema = new Schema({
type: {
type: String,
enum: ['Point'],
required: true,
},
coordinates: {
type: [Number],
required: true,
},
});
export interface Address extends Document {
streetNo: string;
addressStr: string;
country: string;
postalCode: string;
location: Location;
}
const AddressSchema = new Schema<Address>(
{
streetNo: {
type: String,
required: true,
},
addressStr: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
postalCode: {
type: String,
required: true,
},
location: pointSchema,
},
{ timestamps: true }
);
//creating 2dsphere
AddressSchema.index({ location: '2dsphere' });
export const AddressModel = model<Address>('address', AddressSchema);
Now the problem is, I already have a location with these pair of coordinates[41.3326643802915, 19.8263257802915] now I need to add location with these coordinates [41.3326643802986, 19.8263257802456]. So I'm checking these pair is already exists in schema, instead of getting empty result am getting location which has these [41.3326643802915, 19.8263257802915].
Code for checking Existing coordinate:
AddressModel.findOne({
coordinates: { $all: [41.3326643802986, 19.8263257802456]},
}).lean();

How to add GeoJson data with mongoose?

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
}
}
});

geo element must be an array or object: type: "Point"

When I tried post request like this
"{ "imgUrl": "Server\Pictures\i14182109167", "text": "Myself in
seoul", "tag": ["seoul", "tour"], "geometry" : {"type": "Point","coordinates": [80,
-27]} }"
The error causes
'Can\'t extract geo keys: { _id:
ObjectId(\'5b8e204455526366f86a6383\'), tag: [ "seoul", "tour" ],
date: new Date(1536041028423), imgUrl:
"Server\Pictures\i14182109167", text: "Myself in seoul", geometry: {
type: "Point", coordinates: [ 80, -27 ], _id:
ObjectId(\'5b8e204455526366f86a6384\') }, __v: 0 } geo element must
be an array or object: type: "Point"' }
even I added "type": "Point" in post request but, why?
const geoSchema = new Schema({
type: {
type: String,
default: 'Point',
index: '2dsphere'
},
coordinates: {
type: [Number]
}
});
const memoSchema = new Schema({
imgUrl: {
type: String
},
text: {
type: String
},
date: {
type: Date,
default: Date.now
},
tag: {
type: [String]
},
user: {
type: Schema.Types.ObjectId,
ref: 'Memo'
},
geometry: geoSchema
})
I experienced this error, tried several schema declarations, until I fixed by this implementing this design:
1. Create a new schema, which has Point as a property.
const mongoose = require('mongoose');
const {Point} = require('mongoose-geojson-schema');
const pointSchema = new mongoose.Schema({
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
});
2. Schema for the object including above as a property:
const itemsSchema = new mongoose.Schema({
description: {
type: String,
required: true
},
location: {
type: pointSchema,
required: true
}
)
const Item = mongoose.model('Item', ItemsSchema);
module.exports = Item;
enter code here
3. Finally, my controller succesfully instantiates the object like this:
var geolocation =
{
type: 'Point',
coordinates: [
lng,
lat
]
};
const item = new Item({
description: req.body.description,
location: geolocation
})
Hope that helps.
I changed geometry to loc it worked!
but, I don't know why...
I was facing the same issue even after doing everything mention here. After spending too much time on this problem I get to know that if we save a default value it will work correctly.
Just follow the above answer and add
location: {
type: pointSchema,
default: {
type: 'Point',
coordinates: [0, 0],
},
required: false,
},
And delete the previous documents if any document has location.

Mongoose select: false not working on location nested object

I want the location field of my schema to be hidden by default.
I added select: false property to it, but it is always returned when selecting documents...
var userSchema = new mongoose.Schema({
cellphone: {
type: String,
required: true,
unique: true,
},
location: {
'type': {
type: String,
required: true,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
},
coordinates: [Number],
select: false, <-- here
},
});
userSchema.index({location: '2dsphere'});
When calling :
User.find({ }, function(err, result){
console.log(result[0]);
});
the output is :
{
cellphone: '+33656565656',
location: { type: 'Point', coordinates: [Object] } <-- Shouldn't
}
EDIT : Explanation (thanks to #alexmac)
SchemaType select option must be applied to the field options not a type. In you example you've defined a complex type Location and added select option to a type.
You should firstly create locationSchema and after that use schema type with select: false:
var locationSchema = new mongoose.Schema({
'type': {
type: String,
required: true,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
},
coordinates: [Number]
}
});
var userSchema = new mongoose.Schema({
location: {
type: locationSchema,
select: false
}
});

How to update a subdocument inside another subdocument in mongoose using atomic query?

My Mongoose schema looks as follows:
var MousePos = Schema({
x: { type: Number},
y: { type: Number},
clickCount: {type: Number, default:0}
});
var MouseTrackInfo = Schema({
pos:{ type: [MousePos], default:[]},
element: {type: String, index:true},
clickCount:{ type: Number, default: 0 },
timeSpent: { type: Number, default: 0 }
});
var MouseTrackSchema = Schema({
pageUrl: { type: String},
applicationId: { type: String, index: true },
mouseTrackLog: { type: [MouseTrackInfo], default:[]},
urlId: {type: String, index: true}
});
Now what i want to do is to update clickCount in pos subdocument when element, x and y values are specified.
I tried a number of approaches, but nothings seems to be working. Moreover i can't use two $ operator in my query too. Suggestions will be welcome. I want to make this query as atomic as possible.
I was not able to figure out a reliable way so i changed my schema to following:
var MouseTrackInfo = Schema({
element: {type: String, index:true},
clickCount:{ type: Number, default: 0 },
timeSpent: { type: Number, default: 0 },
x: { type: Number, default:0},
y: { type: Number, default: 0},
identifier: {type: String}
});
var MouseTrackSchema = Schema({
pageUrl: { type: String},
applicationId: { type: String, index: true },
mouseTrackLog: { type: [MouseTrackInfo], default:[]},
urlId: {type: String, index: true}
});
MouseTrackSchema.methods.incrementClickCount = function(element,pageX,pageY,cb) {
var parent = this;
this.model('MouseTrackModel').update(
{
'applicationId':this.applicationId,
'urlId':this.urlId,
'mouseTrackLog.identifier': element+"X"+pageX+"Y"+pageY
},
{
'$inc':{'mouseTrackLog.$.clickCount':1}
},
{
'new': true
},
cb);
}
This allowed my execute a atomic query. Any other solution are welcome.

Resources