Mongoose create multiple index and personalize quety to call with specific index - node.js

I would like to do many indexes over my model and when i am doing query use a specific index in that query
this is my model
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var ThingSchema = new Schema({
word:{
type: 'ObjectId',
required:true
},
frecuency:{
type: String,
default:'enabled'
},
document:{
documentId:{
type: 'ObjectId'
},
quality:{
type: Number
}
},
location: {
type: [Number],
index: '2d'
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Thing', ThingSchema);
I would like to have these indexes:
index by word (is a string)
index by location (is geoindex)
index by word and location
Now when I am doing a query I would like to specify which index to use

Before your module.exports line:
ThingSchema.index({word: 1});
// all other indexes you want to add...
And when it's time to make a query, use hint() to specify which index to use:
Thing.find({...}).hint({word: 1});

Related

How to create a dynamic nested mongoose document with the same schema on multiple levels

Before everyone tells me I can't call a const before initializing, I do know that.
But I think this is the simplest way to render the concept I have in mind, (where any subdocument within the replies array also has the same schema as the parent, and documents within the replies array of those subdocuments also having the same schema). I would really appreciate anyone's input.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
var commentSchema = new mongoose.Schema({
content: String,
createdAt: {
type: Date,
default: Date.now
},
score: {
type: Number,
default: 1
},
username: {
type: String,
lowercase: true
},
parent: {
type: Schema.Types.ObjectId,
ref: 'comment'
},
replyingTo: String,
replies: [commentSchema]
});
module.exports = mongoose.model("comment", commentSchema);
Since a const can't be called before initialization, to fix this issue the parent schema should be called on the children array after initialization the code below:
commentSchema.add({ replies: [commentSchema] })
The final result should look like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const commentSchema = new mongoose.Schema({
content: String,
createdAt: {
type: Date,
default: Date.now
},
score: {
type: Number,
default: 1
},
username: {
type: String,
lowercase: true
},
parent: {
type: Schema.Types.ObjectId,
ref: 'comment'
},
replyingTo: String,
});
commentSchema.add({ replies: [commentSchema] })

Mongoose giving error for NOT required Geo spatial field

I am using Mongoose Schema and simplified version looks like:
const newSchema = new mongoose.Schema({
name:{
type: String,
required: true
},
location:{
type: {
type: String,
default: 'Point',
enum: ['Point']
},
coordinates: [Number],
}
});
const newModel = mongoose.model('NewModel', newSchema);
When I try to save a new document using this schema:
newModel.create({
"name": "Default name"
});
It is giving
error:
"Can't extract geo keys: { _id: ObjectId('5e8ed5ddf4781c24d0836b6e'), location: { type: \"Point\" },
name:\"Default name\"} Point must be an array or object"
However, when I fill the location field, it works well. I am wondering why Schema checking for the NOT required field.
var GeoJSON = require('mongoose-geojson-schema');
var mongoose = require('mongoose');
const newSchema = new mongoose.Schema({
name:{
type: String,
required: true
},
location:mongoose.Schema.Types.GeoJSON
});
const newModel = mongoose.model('NewModel', newSchema);
and create data like:
newModel.create({
name: "Default name",
location: {
type: "Point",
coordinates: [longitude, latitude]
}
});
actually the problem occur due to you specified the default type is Point (that pushed by mongoose always if null or not specified) but you did't pass coordinates corresponding, and the point should be with coordinate

How do I index a field on a mongoose Schema that uses a discriminator?

The error started after I started using the discriminator.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Base = require("../config/Base");
const Refill = Base.discriminator(
"Refill",
new Schema({
cylinderSize: { type: Number, required: true },
cylinderSwap: { type: Boolean, required: true },
quantity: { type: Number, required: true },
location: {
type: { type: String },
coordinates: [Number]
}
})
);
Refill.index({ location: "2dsphere" });
module.exports = mongoose.model("Refill");
This returns the error Refill.index is not a function
In Mongoose, indexes must be created on schemas, not models. In your case, the Refill object is a model. One approach is to implement this in three steps:
Create the schema
Add the index to the schema
Create the model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Base = require("../config/Base");
const refillSchema =
new Schema({
cylinderSize: { type: Number, required: true },
cylinderSwap: { type: Boolean, required: true },
quantity: { type: Number, required: true },
location: {
type: { type: String },
coordinates: [Number]
}
});
refillSchema.index({ location: "2dsphere" });
const Refill = Base.discriminator("Refill", refillSchema);
module.exports = mongoose.model("Refill");
I just took out the Refill.index({ location: "2dsphere" }); and the rest of my code is working fine apparently indexing that field wasn't necessary.

How to index mongoose-timestamp in elastic search

We have a mongoose object with schema like following, with the use of timestamps, we are populating createdAt & updatedAt fields. We are using mongoosastic to index these in elastic search.
var mongoose = require("mongoose");
var employeeSchema = new mongoose.Schema(
{
name: {
type: String
es_indexed: true,
es_index:"analyzed"
},
managerId: {type: mongoose.Schema.Types.ObjectId},
details:{},
email: {
type: String
es_indexed: true,
es_index:"analyzed"
},
phone: {
type: Number
es_indexed: true,
es_index:"analyzed"
}
},
{
timestamps: true
});
I want to index updatedAt as well in elastic search, but not sure how to do it with mongoosastic. Please let me know are these specific option to get this done.
Have you tried mapping the date as per the docs?
So, something like
var ExampleSchema = new Schema({
// Date (core type)
createdAt: {type:Date, es_type:'date', es_indexed: true},
updatedAt: {type:Date, es_type:'date', es_indexed: true}
},
{ timestamps: true }
)

MongooseJS: Subdoc Schemas in Separate Files

Let's say that I have a schema called LeagueSchema, which needs to contain some general information about the league (e.g. the name, time created, etc.), as well as some more complicated objects (e.g. memberships). Because these memberships are not needed outside of the league, I don't think it's necessary for them to be their own collections. However, I think for the sake of modularity it would be best for these schemas to live in their own separate files.
It would look something like this:
league.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var LeagueSchema = new Schema({
created: {
type: Date,
default: Date.now
},
updated: {
type: Date,
default: Date.now
},
name: {
type: String,
default: '',
trim: true
},
memberships: [MembershipSchema]
});
membership.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var MembershipSchema = new Schema({
startDate: {
type: Date,
default: Date.now
},
endDate: {
type: Date,
default: null
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
Unfortunately, this doesn't work. I get the following error:
ReferenceError: MembershipSchema is not defined
This is obviously happening because LeagueSchema is dependent on MembershipSchema, but I'm not sure what the best way to include it is. Can I define it as a dependency somehow? Or should I just include the file?
Also, is it bad practice to use subdocuments this way? Is there any reason it would be better to let all of these objects live in their own collections?
In your membership.js, export the membership sub-doc schema as a module:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var MembershipSchema = new Schema({
startDate: {
type: Date,
default: Date.now
},
endDate: {
type: Date,
default: null
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
module.exports = MembershipSchema;
You can then require the exported module schema in your LeagueSchema document:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var MembershipSchema = require('./membership');
var LeagueSchema = new Schema({
created: {
type: Date,
default: Date.now
},
updated: {
type: Date,
default: Date.now
},
name: {
type: String,
default: '',
trim: true
},
memberships: [MembershipSchema]
});
To answer your second question, as a general rule, if you have schemas that are re-used in various parts of your model, then it might be useful to define individual schemas for the child docs in separate files as so you don't have to duplicate yourself. A good example is when you use subdocuments in more that one model, or have two fields in a model that need to be distinguished, but still have the same subdocument structure.
If your memberships are not used elsewhere then rather treat the schema as an embedded document (document with schema of its own that is part of another document, such as items within an array):
Example definition and initialization:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var MembershipSchema = new Schema({
startDate: {
type: Date,
default: Date.now
},
endDate: {
type: Date,
default: null
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
var LeagueSchema = new Schema({
created: {
type: Date,
default: Date.now
},
updated: {
type: Date,
default: Date.now
},
name: {
type: String,
default: '',
trim: true
},
memberships: [MembershipSchema]
});
mongoose.model('League', LeagueSchema);
Your membership.js file should export the schema and the league.js file should import it. Then your code should should work.
In membership.js towards the bottom add:
module.exports = MembershipSchema;
In league.js, add
var MembershipSchema = require('membership.js');

Resources