Mongoose, index locations array - node.js

I have an array of locations in a document and I want to add a 2dSpere index on that array. Is that possible?
var LocationSchema = new Schema({
type: { type: String, required: true },
geometry: {
type: { type: String, required: true },
coordinates: { type: Array, required: true}
},
properties: Schema.Types.Mixed
});
// Collection to hold users
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
locations: [LocationSchema]
},{
versionKey: false
}
);
How do I add a 2DSphere index on the geometry field in the locations array?

https://github.com/LearnBoost/mongoose/blob/master/examples/geospatial/geoJSONSchema.js#L19
LocationSchema.index({ 'geometry' : '2dsphere' });

If you store values for location as 2 numbers in array, then your index would look like:
coordinates: { type: [Number], index: '2dsphere', required: true }
Although you need to create such index in your database:
db.users.ensureIndex({ 'locations.geometry.coordinates': '2dsphere' });

Related

How to create multiple index in mongoose schema

I'm trying to add multiple compound unique index in mongoose schema, but only the first schema.index() is working independent if I change the order.
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
const PrivilegeSchema = new mongoose.Schema({
application: {
type: Schema.Types.ObjectId,
required: true,
ref: 'Application',
autopopulate: true
},
section: {
type: String,
required: false
},
title: {
type: String,
required: false
},
permission: {
type: String,
required: true
},
active: {
type: Boolean,
required: true
}
});
PrivilegeSchema.index( { permission: 1, application: 1 }, { unique: true, partialFilterExpression: {active: true} } );
PrivilegeSchema.index({ section: 1, title: 1, application: 1 }, { unique: true, partialFilterExpression: {active: true} });
export { PrivilegeSchema };
How can I set both schema index
I found the issue, the existing data in the collection is restricting the index to be created. Hence the following validation is throwing.
I removed whole data from the collection and now both the index got created.

Mongoose Geolocation set default coordinates

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

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

How to select a value from an array in mongoose schema

Using MongoDb version 3.2.7
I have a mongoose schema like this which has an array of stock in branch schema. I want to select a subCategoryId in stock array and get the currentPrice of that subCategoryId only, for that I am using query
var getCriteria = { "stock.subCategoryId": subCategoryId }
var update = { "stock.$.currentPrice": currentPrice }
This query works for me at the time of updating the value as I am able to update the currentPrice of selected subCategoryId perfectly. But when I want to get a price of particular subCategoryId the following query gets me all the stocks in the branch collection. The query I am using is this:
var getCriteria ={ "stock.subCategoryId": subCategoryId }
Mongoose Schema
var branch = new Schema({
branchName: { type: String, trim: true, index: true, default: null },
isBlocked: { type: Boolean, default: false, required: true },
email: { type: String, trim: true, required: true, unique: true, index: true },
password: { type: String, required:true },
accessToken: { type: String, trim: true, index: true, unique: true, sparse: true },
stock: [stock],
});
var stock = new Schema({
categoryId: { type:Schema.ObjectId, ref: "categoies", default: null },
subCategoryId: { type:Schema.ObjectId, ref: "subCategories", default: null },
currentPrice: { type: Number },
isBlocked: { type: Boolean, default: false, required: true },
Date: { type: Date, default: Date.now, required: true }
});
To retrieve only the matching array element try this:
branch.find(getCriteria,{'stock.$' : 1},function(err,branch){...});
stock.$ will help you to retrieve only the matched element from the array.

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

Resources