mongoose isModified functionIn a hook I want to confirm whether a password has changed before executing encryption process. Mongoose has a function "isModified" and I believe Sequelize's "changed" function servers the same purpose.
I cannot get the "changed" function to work. I am looking for an example of how it is used.
There is an example of how changed() works in the official documentation
const mdl = await MyModel.findOne();
mdl.myJsonField.a = 1;
console.log(mdl.changed()) => false
await mdl.save(); // this will not save anything
mdl.changed('myJsonField', true);
console.log(mdl.changed()) => ['myJsonField']
await mdl.save(); // will save
Keep in mind that changes are detected for the top-level fields and only for changes that were made since the last save call.
Related
I would like to modify a document field's data prior to it being validated by mongoose, like so:
mySchema.pre("validate", function (next) {
this.myField = "yay a new value prior to validation" // doesn't work for me
next();
});
Unfortunately, that doesn't work for me. The example above is simplified, in my project I'm trying to prevent an ObjectParameterError from crashing my server, and assigning values in my pre-validate hook doesn't work for me.
Try using .set() method of mongoose Document to access value. Your code should be changed this way
mySchema.pre("validate", function (next) {
this.set("myField", "yay a new value prior to validation")
next();
});
I'am using mongoose-ttl node package to clear the collections. But I'am getting this warning.
(node:4768) DeprecationWarning: collection.remove is deprecated. Use deleteOne, deleteMany, or bulkWrite instead.
I'am not using any methods like remove() etc.But I can't understand from where this warning is thrown.
Please suggest me any method to remove this warning.
TTL Code goes here:
var mongoose = require("mongoose");
var ttl = require('mongoose-ttl');
var OTPStore = new mongoose.Schema({
OTPNo: {
type: Number,
require: true
}
});
OTPStore.plugin(ttl, { ttl: '30m', interval: '30m'});
module.exports = mongoose.model("OTPStore", OTPStore);
Thank you.
Looks like you wanna delete something from db.
const store=await OTPStore.deleteOne({_id:id}) //this will find the first one and delete
const store=await OTPStore.deleteMany({ _id:id })
//this will delete all. This used for properties that some of the instances have others not. For example if you had "isExpensive" property in your schema you could pass {isExpensive:true} and mongose would find all the instances that meet this criteria and remove them
const store=await OTPStore.findByIdAndRemove(id)
// if you notice in above examples I passed an object. But here you are already notifying mongooose that you are querying by id, so just put an id as argument
NOTE that this operations are async operations so in order to use await, make sure wrapper function should start with async function
MongoDB version 3.6.7, mongoDB node.js driver version 3.1.10.
Have a function which should add some data to the db in a bulk unordered operation. When bulk.execute() is called the data is inserted into the DB as have manually checked this is the case, however the bulkWriteResult object which should be generated as a result of the execution isn't being returned.
We need that for use in other functions to determine the number of insertions etc. So when the function in question is chained in other functions it returns undefined, when adding bulk.execute().then(console.log) also nothing is logged to the terminal.
The function takes 3 parameters, the MongoClient, the name of the collection and the documents to be inserted into the DB which is an array of documents.
Have also tried adding err and result callbacks too with no luck, none of the console.logs are reached.
batch.execute((err, result) => {
console.log('RESULT INSERTED:', result.nInserted)
console.log('RESULT ERRORS:', result.getWriteErrorCount())
console.log('RESULT INSIGHTS:', result.getWriteErrors())
console.log('ERROR:', err)
})
Any ideas why the bulkWriteResult would not be returned yet the bulk insertion is successful?, function was working and returning the expected object prior to upgrading the mongoDB node driver to 3.1.10.
const insertManyMissingEntries = (database, collectionName, documents) => {
const db = database.db('data')
const collection = db.collection(collectionName)
const batch = collection.initializeUnorderedBulkOp()
documents.forEach(doc => {
batch
.find({ year: doc.year, month: doc.month, code: doc.code })
.upsert()
.updateOne({ '$setOnInsert': doc })
})
return batch.execute()
}
Here is your function
const insertManyMissingEntries = (database, collectionName, documents) => {
if (documents.length === 0)
return Promise.reject('documents length is zero')
const operations = documents.map((doc) => {
const filter = {year: doc.year, month: doc.month, code: doc.code}
const update = {$setOnInsert: doc}
return {updateOne: {'filter': filter, 'update': update, 'upsert': true}}
})
const db = database.db('data')
const collection = db.collection(collectionName)
const bulkOptions = {ordered: false}
return collection.bulkWrite(operations, bulkOptions)
}
If documents parameters is empty i.e. length = 0 the collection bulk write function will always fail. Watch it.
Also you need to make sure you have index on fields year, month, code or your bulk will be executing slow because it will every time it will perform a collection scan to find a document.
Remember,
driver docs is your best friend
http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html
There wasn't a way to resolve this issue though we believe it was caused by a docker mongo image version not being the official one or out of date. Even the folks at mongoDB weren't able to replicate this or explain any circumstances where a promise should fail to either resolve or reject within the timescales the functions were working to so like many things it remains a mystery that we had to workaround by basically using a ternary to handle the undefined that resulted from the promise error without ever actually solving the underlying issue - not ideal or best practice but in absence of other options it's what we did.
Thanks for everyone's help and comments to try to resolve it, much appreciated.
First time working with MongoDB and Mongoose.
I have written an edit function which do something with the input params and then call an update on the model:
edit: function (input) {
var query = ...
var document = ...
return Model.update(query, document, {multi: true});
}
The function return a Promise with the number of affected documents.
I know that the Mongoose update function
updates documents in the database without returning them
so I was wondering if there is a way to somehow:
run my edit function
if everything goes well, run a find on the model in order to retrieve the updated documents, and return the find's Promise.
Any help would be appreciated.
Currently I am using pre('save') to do validation:
UserSchema.pre('save', true, function(next, done) {
var self = this //in case inside a callback
var msg = helper.validation.user.username(self.username)
if (msg) {
self.invalidate('username', msg)
done(helper.getValidationError(msg))
}
else
done()
next()
})
The helper module has a function that accepts an input and returns error message.
exports.user = {
username: function(input) {
if (!input)
return 'username is required'
var min = 3
var max = 10
if (input.length < min)
return 'username min of length is ' + min
if (input.length > max)
return 'username max of length is ' + max
return null
}
}
There is another api validate to do similar things. What's the difference between them and which one should I use in what cases?
Update:
The validation is performed before the user defined hooks. You can follow this github post, where the contributor states,
not implementing this. validating first gives us a chance to stop
before continuing into user defined hooks which may include async
updates to other collections.
if we need validation to run again after we make a change from inside
a hook we can always manually run this.validate(next).
Outdated:
Yeah, there is a small difference i know.
Pre hooks are executed before validations.
There is a closed issue on github asking for validation before pre hooks, https://github.com/Automattic/mongoose/issues/400.
And also there is a reason for not having validation before pre hooks, stated in the same link by #kamholz:
Say you have two fields, foo and fooSort, both are required. fooSort is a
lowercased or otherwise transformed version of foo to be used in
sorting. Since fooSort can be automatically generated, it makes sense
to do so in a pre-save hook. But since validation runs first, it will
fail before the pre-save hook runs and has a chance to fill in the
fooSort value. It isn't a question of being able to run validation
again manually.
Again, if you want to validate something and then need the hook for post validate:
UserSchema.post('validate', function(next){
console.log("post validate called");
next();
});
So for summary, the one difference i see is,
you can use both as long as you get inputs to save in db directly without altering anything (only validation).
If you are altering anything you have to use pre save hook.
The above answer is incorrect. If you go to: https://github.com/Automattic/mongoose/issues/400 and read the responses to the topic from the mongoose contributor you'll see that he notes they are run before on purpose.
The topic is named: Validation should run after all other pre-save hooks
Mongoose contributor aheckmann states that:
right now its running before them
not implementing this. validating first gives us a chance to stop before continuing into user defined hooks which may include async updates to other collections.