Mongoose unique validation error even though unique constraint is not there - node.js

var schema = new Schema({
_id: Schema.ObjectId,
email: {type: String, required: true}
});
Previously email field was unique (with unique constraint)
Now I removed unique constraint, then also it's giving unique validation error. I have restarted mongo then also it's throwing error.
Any Idea?

When you remove the unique constraint in the schema definition, you were supposed to manually remove it from the database as well. You can do this either in mongo shell by using the dropIndex() method or in your application using the native node.js driver's dropIndex() method of the collection.
You may need to confirm this first by checking the indexes currently in the database; you will most probably find the email unique index created when you populated the collection after defining the schema in Mongoose.
You can issue the command in mongo shell, supposing you have a collection named users in your database named test:
> db.users.getIndexes()
which will show the current indexes, you may see in your console an array like the following:
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.users"
},
{
"v" : 1,
"unique" : true,
"key" : {
"email" : 1
},
"name" : "email_1",
"ns" : "test.users",
"background" : true,
"safe" : null
}
]
For a solution in your application code, supposing you have a Mongoose model called User that has the defined schema above, you can call the getIndexes() native node.js driver's collection method:
User.collection.getIndexes(function (err, results) {
// Handle errors
});
In mongo shell, you can then go ahead and remove the email index with the dropIndex() method :
> db.users.dropIndex("email_1")
In your application code, you can also issue the command via the Mongoose model for the collection, and call the native node.js driver's dropIndex() method of the collection:
User.collection.dropIndex("email_1", function (err, results) {
// Handle errors
});

You can also follow the below steps.
Delete users collection from database.
Save user model(Schema) file and test.

Related

push all element of array in subdocument while saving document

I want to push elements of array to create subdocument,
my schema
var chatGroup = new Schema({
name : {
type : String,
default : null
},
members: {
type : [subSchemaForMember]
},
}, { collection: 'chatGroup' });
var subSchemaForMember = new Schema({
user_id : {type : Schema.Types.ObjectId , ref : 'user'}},{_id : false});
my query to save document is
var chatGroup = new ChatGroup({
name : req.body.name,
image : req.body.image,
created_by : req.body.celebrity_id,
$pushAll : {'members' : req.body.members}
})
where req.body.memebers = ['someid','someid','someid']
Please help I want to do it without any loop
I don't see you actually saving the document, only calling new on the constructor. You need to explicitly call save. on the object after you construct it. For the documentation on creating documents, see here: http://mongoosejs.com/docs/models.html.
Also, the use of $pushAll only applies when you have an object already in mongodb, which has existing values, and you want to retain those values and push additional values onto the array (so in your example you can simply assign the array to members).
Also of note is that the current mongoose documentation indicates that $pushAll is deprecated and you should be using $push together with $each, but the same rules apply, see here:
https://docs.mongodb.com/manual/reference/operator/update/push/#append-multiple-values-to-an-array

Mongodb prevent empty values while updating

I have a collection of words, the scheme is as follows:
var wordsSchema = new Schema({
name : { type : String , trim : true , required : true , unique : true , index: true},
definition : { type : String , trim : true , required : true }
});
when I try to save new word with empty name or definition into collection required: true works end return error,but when I try to update collection and set empty name or definition value required:true doesn't works and updated word with empty fields saves into collection I want to prevent saving empty words into collection. How can I achieve this with a shortest way, My Update code looks like this:
words.update({ _id : word._id }, { $set : {
name : word.name,
definition : word.definition
}
} , function(err,data) {
if(err) {
res.status(1033).send("There was error while changing word");
} else {
res.send('Word has successfully changed');
}
});
required:true is not something maintained at the database level, but rather mongoose itself handles that for you. when you do an update operation, mongoose doesn't run your validators (required:true is a type of validator).
There is a change coming up in mongoose 4 where validators get run on updates. For now, your options are
manually check if there's nothing there (enforced by your application)
do a find on the document, then edit the field and do doc.save which will run validators (enforced by mongoose)
add a document with an empty value for 'word'. because you have a unique index on that field, mongodb will not allow you to insert another document without a value for that field (enforced by mongodb)
I would recommend that last option.

How to guarantee unique subdocs by date in Mongo/Mongoose? [duplicate]

For my project, I want to keep a mongoose document for groups of organizations, like this:
var groupSchema = Schema({
name : { type : String },
org : { type : Schema.Types.ObjectId, ref : 'Organization' },
...
users : [{
uid : { type : Schema.Types.ObjectId, ref : 'User' },
...
}]
});
I want to prevent the same user from being in the same group twice. To do this, I need to force users.uid to be unique in the users array. I tried stating 'unique : true' for uid, but that didn't work. Is there a way to do this with mongoose or mongoDB without extra queries or splitting the schema?
Edit:
I changed the previous value of uid to
uid : { type : Schema.Types.ObjectId, ref : 'User', index: {unique: true, dropDups: true} }
But this still doesn't seem to work.
Edit: Assuming there is no simple way to achieve this, I added an extra query checking if the user is already in the group. This seems to me the simplest way.
A unique index on an array field enforces that the same value cannot appear in the arrays of more than one document in the collection, but doesn't prevent the same value from appearing more than once in a single document's array. So you need to ensure uniqueness as you add elements to the array instead.
Use the $addToSet operator to add a value to an array only if the value is not already present.
Group.updateOne({name: 'admin'}, {$addToSet: {users: userOid}}, ...
However, if the users array contains objects with multiple properties and you want to ensure uniqueness over just one of them (uid in this case), then you need to take another approach:
var user = { uid: userOid, ... };
Group.updateOne(
{name: 'admin', 'users.uid': {$ne: user.uid}},
{$push: {users: user}},
function(err, numAffected) { ... });
What that does is qualify the $push update to only occur if user.uid doesn't already exist in the uid field of any of the elements of users. So it mimics $addToSet behavior, but for just uid.
Well this might be old question but for mongoose > v4.1, you can use $addToSet operator.
The $addToSet operator adds a value to an array unless the value is already present, in which case $addToSet does nothing to that array.
example:
MyModal.update(
{ _id: 1 },
{ $addToSet: {letters: [ "c", "d" ] } }
)

MongoDB _id is convert to ObjectID automatically, but sometime it is not.

I am using a wrapper called mongoskin to access mongoDB. mongoskin is a simple wrapper around mongoDB javascript api.
But when I write to mongoDB, sometimes _id is converted to ObjectID, sometime is it not. The different behavior causes many problem when I have to compare _id. For example:
The following documents in company collection, "creator" is not converted to ObjectID, but item in "clients" is converted to ObjectID automatically.
> db.company.find()
{ "_id" : ObjectId("53d4b452f5b25900005cb998"), "name" : "Default Company Co.", "clients" : [ ObjectId("53d4b452f5b25900005cb999"), ObjectId("53d4b452f5b25900005cb99a") ] }
{ "_id" : ObjectId("53d4b452f5b25900005cb999"), "name" : "client company for 777 - updated", "creator" : "53d4b452f5b25900005cb998", "ssn" : "12-123-1234" }
This is the nodejs code I used to assign _id for "creator"
clientCompany.creator = req.session.user.company_id;
This is the nodejs code I used to assign _id for "clients"
var updateObj = {$addToSet: {clients:resultClient._id} };
// update creator company.clients
creatorCompany.update(updateObj, function(err, result) { ...}
When I console.log "req.session.user.company_id" and "resultClient._id", they both looks like a string type. How come one end up as ObjectID in MongoDB? If there is an auto conversion, how do I make this behavior consistent?
Thanks!
I'm guessing resultClient is the result of a query and req.session.user.company_id a string from your web application? In that case you need to create an ObjectId from the string:
clientCompany.creator = mongoskin.ObjectID(req.session.user.company_id);

Mongoose Unique values in nested array of objects

For my project, I want to keep a mongoose document for groups of organizations, like this:
var groupSchema = Schema({
name : { type : String },
org : { type : Schema.Types.ObjectId, ref : 'Organization' },
...
users : [{
uid : { type : Schema.Types.ObjectId, ref : 'User' },
...
}]
});
I want to prevent the same user from being in the same group twice. To do this, I need to force users.uid to be unique in the users array. I tried stating 'unique : true' for uid, but that didn't work. Is there a way to do this with mongoose or mongoDB without extra queries or splitting the schema?
Edit:
I changed the previous value of uid to
uid : { type : Schema.Types.ObjectId, ref : 'User', index: {unique: true, dropDups: true} }
But this still doesn't seem to work.
Edit: Assuming there is no simple way to achieve this, I added an extra query checking if the user is already in the group. This seems to me the simplest way.
A unique index on an array field enforces that the same value cannot appear in the arrays of more than one document in the collection, but doesn't prevent the same value from appearing more than once in a single document's array. So you need to ensure uniqueness as you add elements to the array instead.
Use the $addToSet operator to add a value to an array only if the value is not already present.
Group.updateOne({name: 'admin'}, {$addToSet: {users: userOid}}, ...
However, if the users array contains objects with multiple properties and you want to ensure uniqueness over just one of them (uid in this case), then you need to take another approach:
var user = { uid: userOid, ... };
Group.updateOne(
{name: 'admin', 'users.uid': {$ne: user.uid}},
{$push: {users: user}},
function(err, numAffected) { ... });
What that does is qualify the $push update to only occur if user.uid doesn't already exist in the uid field of any of the elements of users. So it mimics $addToSet behavior, but for just uid.
Well this might be old question but for mongoose > v4.1, you can use $addToSet operator.
The $addToSet operator adds a value to an array unless the value is already present, in which case $addToSet does nothing to that array.
example:
MyModal.update(
{ _id: 1 },
{ $addToSet: {letters: [ "c", "d" ] } }
)

Resources