Unique in mongoose not working as expected - node.js

I have my example mongoose schema as below
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const exampleSchema = new Schema ({
name:{
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
mobile:{
type: String,
required: true,
unique: true
}
})
module.exports ={Driver: mongoose.model('Driver', driverSchema)}
Now the thing is that unique in mobile is working fine, but in email it allows me to insert duplicate email address.

You had better to create your indexes in mongodb shell.
In the mongoose docs they state:
In a production environment, you should create your indexes
using the MongoDB shell rather than relying on mongoose to do it for
you. The unique option for schemas is convenient for development and
documentation, but mongoose is not an index management solution.
So I would remove unique options in schema, and can create the unique indexes in mongodb shell like this:
db.drivers.createIndex( { "email": 1 }, { unique: true } )
db.drivers.createIndex( { "mobile": 1 }, { unique: true } )

It was due to I have records in collection before giving unique: true.

Related

Mongoose aggregate and append

I have a Mongo DB (latest version) that I am accessing with Mongoose (v6.5.4)
The project is using a discriminator pattern to keep all documents in the same collection.
There are many instances where i need to join documents.
Set up:
// Models:
const UserSchema = new Schema<IUser>(
{
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
});
// There are other similar models to <Team>
const TeamSchema = new Schema<ITeam>(
{
name: {
type: String,
required: true,
},
userIds: {
type: [Schema.Types.ObjectId],
required: true,
ref: "User",
default: [],
},
});
Problem:
I can use populate to return collections of Teams and the userIds be an array of user objects.
Where I am stuck is querying getting an array of users with an added field of teams[].
I've been trying aggregate to no success, I can loop over the users collection and return a list of Teams but this feels wrong and expensive in terms of read units (production data base is on a pay as you go service)
As data models go there is not much going for it - but it is an existing solution
Can anyone advise?
I was being stupid. The from field in my look up was wrong.
Should have been 'teams' not 'Team' which is the model name.

Mongoose - Exclude the fields that are in DB and not in Mongoose Schema

We are creating a NodeJS API using Express Framework with backend datastore as Mongo DB. We are using Mongoose package for interacting with the Mongo Database. The Mongoose Schema is as below:
const user = new Schema(
{
id: { type: String, immutable: true },
firstName: { type: String, maxlength: 100 },
lastName: { type: String, maxlength: 100 },
email: { type: String, maxlength: 500 },
},
{
timestamps: true,
strict: true
});
We have used the strict: false so that fields that are not defined in the schema are not getting saved to Mongo. We also need to ensure that if there are some extra field in the User Document in the Mongo Database, that will not be exposed as part of the User Get. We could see that find() operation accepts are option to select the field that needs to be excluded. Is there a way other than that to make the API responses inline with the Mongoose Schema defined above?

Mongoose Index on a field in nested document

I have a small schema
var PostSchema = new mongoose.Schema({
title: String,
link: String,
author: {type:String,required:true},
upvotes: {type: Number, default: 0},
nesteddoc : {
field1: String
}
});
//This is broken - index on field1
PostSchema.index({nesteddoc.field1:1},{unique:true});
Is it possible to have an index on nested field by specifying in Mongoose schema and not running a MongoDB query to ensure the index ?
Use quotes around "nesteddoc.field1" to evaluate the nested field :
PostSchema.index({ "nesteddoc.field1": 1 }, { unique: true });
Furthermore, mongoose will call ensureIndex internally, from mongoose doc :
When your application starts up, Mongoose automatically calls
ensureIndex for each defined index in your schema. Mongoose will call
ensureIndex for each index sequentially, and emit an 'index' event on
the model when all the ensureIndex calls succeeded or when there was
an error. While nice for development, it is recommended this behavior
be disabled in production since index creation can cause a significant
performance impact. Disable the behavior by setting the autoIndex
option of your schema to false, or globally on the connection by
setting the option config.autoIndex to false.
You can also define index in schema :
var PostSchema = new mongoose.Schema({
title: String,
link: String,
author: { type: String, required: true },
upvotes: { type: Number, default: 0 },
nesteddoc: {
field1: { type: String, unique: true, index: true },
}
});

Unable to check whether the value exists inside nested Model in mongoose

I am creating poll app. My schema definitions are as below
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/pollApp');
var userSchema = new mongoose.Schema({
username: { type: String, required: true},
phonenumber: { type: String, required: true, unique: true}
});
var option = new mongoose.Schema({
title: {type: String, required: true},
votes: { type: Number, default: 0 },
voterList: {type: []}
});
var poll = new mongoose.Schema({
question: { type: String, required: true, unique: true},
options: { type: [option], required: true},
showVoters: {type: Boolean, default: false}
});
mongoose.user = mongoose.model('User', userSchema);
mongoose.poll = mongoose.model('Poll', poll);
module.exports = mongoose;
voterList will contain all the voters name.Before adding vote i want to check whether user has already voted for the poll(need to check user exists in each voterList array). How to accomplish this?
If you want unique values in the voterList array, you can use $addToSet for pushing a user in the voterList.
but if you want to do some kind of validation. It is better you do a get query which checks if user is already present in the array.
if yes, throw a message saying user already voted else add the user to voterlist
For checking an user is already present in voterList array, it is very simple actually.
You can use a find query like below:
find({voterList:'585ce839c84f5d3d1ef15d56'})
Even if voterList is an array, mongo will see if the provided value is present in the array or not.

What is the "__v" field in Mongoose

I'm using Mongoose version 3 with MongoDB version 2.2. I've noticed a __v field has started appearing in my MongoDB documents. Is it something to do with versioning? How is it used?
From here:
The versionKey is a property set on each document when first created
by Mongoose. This keys value contains the internal revision of the
document. The name of this document property is configurable. The
default is __v.
If this conflicts with your application you can configure as such:
new Schema({..}, { versionKey: '_somethingElse' })
Well, I can't see Tony's solution...so I have to handle it myself...
If you don't need version_key, you can just:
var UserSchema = new mongoose.Schema({
nickname: String,
reg_time: {type: Date, default: Date.now}
}, {
versionKey: false // You should be aware of the outcome after set to false
});
Setting the versionKey to false means the document is no longer versioned.
This is problematic if the document contains an array of subdocuments. One of the subdocuments could be deleted, reducing the size of the array. Later on, another operation could access the subdocument in the array at it's original position.
Since the array is now smaller, it may accidentally access the wrong subdocument in the array.
The versionKey solves this by associating the document with the a versionKey, used by mongoose internally to make sure it accesses the right collection version.
More information can be found at: http://aaronheckmann.blogspot.com/2012/06/mongoose-v3-part-1-versioning.html
For remove in NestJS need to add option to Schema() decorator
#Schema({ versionKey: false })
It is possible to disable the version key if you don't need it.
See this example:
var User = new mongoose.Schema({
FullName:{
type :String,
},
BirthDay:{
type :String,
},
Address:{
type :String,
},
Gender:{
type:String,
},
PhoneNumber:{
type:Number,
ref:'Account'
},
AccountID:{
type: Schema.Types.ObjectId,
ref: 'Account'
},
UserName:{
type:String,
ref:'Account'
}
},{collection:'User',
versionKey: false //here
});
It is the version key.It gets updated whenever a new update is made. I personally don't like to disable it .
Read this solution if you want to know more
[1]: Mongoose versioning: when is it safe to disable it?
the '__v' field in our 'document' serves 'optimisticConcurrency' concerns.
This term basically means in mongoose :
let, you grabed a document by 'findOne, findById' but not used save() method of mongoose yet. and what if at this interval, any other code grabed same document and used .save() method before the first document instance.
at this use case, if we want to (mongoose specific) throw a version error kinda thing, we use optimisticConcurrency: true option in schema.
and then mongoose will use '__v1' to compare these two document.
without optimisticConcurrency: true option. '__v' has no has no effect. and mongoose will not increase it by 1.
Note : in 'findOneAndUpdate' kinda operations, will not update '__v'. (only save() updates)
The __v field is called the version key. It describes the internal revision of a document. This __v field is used to track the revisions of a document. By default, its value is zero (__v:0).
If you don't want to use this version key you can use the versionKey: false as mongoose.Schema parameter.
You can follow this example...
const mongoose = require('mongoose');
const userSchema = mongoose.Schema(
{
name: {
type: String,
require: true
},
email: {
type: String,
unique: true
},
password: {
type: String,
}
},
{
timestamps: true,
versionKey: false, // Here You have to add.
}
)
module.exports = mongoose.model('tbl_user', userSchema)
We can use versionKey: false in Schema definition
'use strict';
const mongoose = require('mongoose');
export class Account extends mongoose.Schema {
constructor(manager) {
var trans = {
tran_date: Date,
particulars: String,
debit: Number,
credit: Number,
balance: Number
}
super({
account_number: Number,
account_name: String,
ifsc_code: String,
password: String,
currency: String,
balance: Number,
beneficiaries: Array,
transaction: [trans]
}, {
versionKey: false // set to false then it wont create in mongodb
});
this.pre('remove', function(next) {
manager
.getModel(BENEFICIARY_MODEL)
.remove({
_id: {
$in: this.beneficiaries
}
})
.exec();
next();
});
}
}

Resources