Mongodb prevent empty values while updating - node.js

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.

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

Mongoose unique validation error even though unique constraint is not there

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.

Mongoose find with default value

I have a mongoose model: (With a field that has a default)
var MySchema= new mongoose.Schema({
name: {
type: String,
required: true
},
isClever: {
type: Boolean,
default: false
}
});
I can save a model of this type by just saving a name and in mongoDB, only name can be seen in the document (and not isClever field). That's fine because defaults happen at the mongoose level. (?)
The problem I am having then is, when trying to retrieve only people called john and isClever = false:
MySchema.find({
'name' : 'john',
'isClever': false
}).exec( function(err, person) {
// person is always null
});
It always returns null. Is this something related to how defaults work with mongoose? We can't match on a defaulted value?
According to Mongoose docs, default values are applied when the document skeleton is constructed.
When you execute a find query, it is passed to Mongo when no document is constructed yet. Mongo is not aware about defaults, so since there are no documents where isClever is explicitly true, that results in empty output.
To get your example working, it should be:
MySchema.find({
'name' : 'john',
'isClever': {
$ne: true
}
})

$unset is not working in mongoose

My schema is as follows : -
var Schema1 = new mongoose.Schema({
name: String,
description: String,
version: [{
id: String,
status: Number
}]
});
I want to unset the version field. I try the following code :-
Schema1.update({}, {
$unset: {
version: 1
}
}, {
multi: true
}).exec(function(err, count) {
console.log(err, count)
});
It gives me the following output :-
null 10
But the output contain the version field :-
{
name : 'a',
description : 'sdmhf',
version : []
}
The above code remove the data but I want to remove the version field from my collection as well. Can you tell me how to do that?
There's nothing wrong with your code. Mongoose is actually deleting those fields in the documents (which I assume is what you expected). You can see by opening a mongo shell into your database and searching all your documents before and after the update (use db.yourcollection.find({}))
Why does an empty array still appear even when it's removed from every document in the collection? Mongoose will ensure the documents returned will obey the schema that you define. So even if Mongoose finds no version property pointing to an Array in the actual document, it will still present an empty array when the matching documents are returned.
You can verify this yourself by adding some arbitrary property (pointing to an Array) to your schema and running a .find({}) again. You'll see that Mongoose will return these properties in every document even though you never saved them to the database. Similarly, if you add non-Array properties like Strings, Booleans, etc, Mongoose will return those as long as you specify a default value.
If you want to drop version for good (as you mentioned in your comment) you can drop it from your Mongoose schema after you've completed the $unset.
This worked for me
doc.field = undefined
await doc.save()

Increasing one field in a MongoDB collection with Mongoose

I'm trying to increment a value in a collection in my MongoDB database through Mongoose. This is the demo code shown on the Mongoose website:
var conditions = { name: 'borne' }
, update = { $inc: { visits: 1 }}
, options = { multi: true };
Model.update(conditions, update, options, callback)
And I have something like this:
var conditions = { "uniqueId" : itemId };
var update;
if(increase)
update = {$inc : {inStock : 1}};
else
update = {$dec : {inStock : 1}};
Item.update(conditions, update, {}, callback);
As you can see there is not much difference from the Mongoose's website code.
The problem is that when this piece of code is executed, I end up having in my collection one field called $dec (or $inc) which has an object as a field in the form {inStock : 1}. I just would like to increment the inStock entry of the collection. In the Schema I have:
var ItemToSell = new Schema({
uniqueId : { type: Number, index: true }
, name : String
, type : String
, inStock : Number
});
Can anyone point out what am I doing wrong?
Thanks a lot.
A) Make sure you're Mongoose is up-to-date. Older versions were very buggy on Model.update operations because Mongoose attempts to infer when you are merely passing a new object, in which case it turns your update object into a $set operation.
B) Try removing the empty {} from your function call. It is optional, and by passing an empty object rather than actual options, you may be confusing Mongoose into setting the { safe: false } option, which could also be causing your problem. I have not checked the source code to confirm that that could be the issue, but it's probably worth a try.

Resources