Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js Mongoose, how to catch error in post save

I have a collection with a unique field on it. Let's say I create the value of this unique field in the pre save method like this:

schema.pre('save', function (next) {
    var _self = this;
    try {
        if (config.devMode) {
            log.debug('[' + si.name + ':write] - Executing presave on: ' + _self._id);
        }
        if(!_self.transaction_id){
            _self.transaction_id = powm(30).toLowerCase();
        }
        next();
    } catch (e) {
        log.error('[' + si.name + ':write] - threw an error (SAVE): ', e.stack, _self);
        next(e);
    }
});

Powm creates an aleatory string like 'dfjkfj3434jkl23k4j2k3j4asdf', which needs to be unique. Although the string is long enough to not be duplicated, I want to be sure that if it is I can retry the saving with a new one till there is a really unique value on it.

I know MongoDB throws an error that bubbles up when saving the document like this:

documentname.save(function(err, doc){
   // If mongodb unique error then reset with a new id and resave
});

But this forces me to look for all places in the code where this happens. So I was wondering if I can catch this error in the post mongoose middleware. The problem is that no error object seems to be passed to post save method. So, any idea on this? Thanks!

like image 930
R01010010 Avatar asked Nov 09 '22 14:11

R01010010


1 Answers

I'm answering with what I found out right now by stumbling on a similar issue.

I'll be focusing in the "catch error in post save" part as I'm not sure, by now if modifying and re-saving the document in this way might or might not cause some trouble. So I'm not sure this will work fine for your specific needs, but you can give it a try.

My scenario is similar to yours, but slightly different:

  1. I want to associate an unique, random, short code to each document of my collection.
  2. I do not generate it randomly at each insertion, but I pre-generated a collection of 1M random codes stored in documents like this:

    {
      value: "khsda",
      status: "FREE"
    }
    
  3. Each time I want to insert a new document with an associated code I do the fallowing:

    1. In .pre('validate',...) I select a "FREE" code and set its status to "PENDING".
    2. I assign the new document code to the value of the picked code.
    3. Now, if the saving process goes fine I want to change the status to "TAKEN" otherwise, I want to freed the code, setting its status back to "FREE".
    4. To know If everything went fine, I hook a .post('save',...) middleware that changes the code status to "TAKEN"
    5. To know If something went wrong, I hook a .post('validation',...) middleware. But here's the quirk: the signature of the function I pass to the middleware must be function(error, doc, next). This middleware will be called only if an error occurs in the validation process and lets me put back the status of the code to "FREE".

So, basically, you could hook a middleware like this:

schema.post('save', function(err, doc, next) {
    // Handle the error...
});

I'm not sure if attempting to change and re-save the document at this point will cause any issue, but by logic, the save operation should already have been aborted and here you can control the bubbling of the error through the next(). If you attempt a new save and then call next() without any error as argument, It might work as you need.

Let me know if this works.

like image 116
Carlo Moretti Avatar answered Nov 14 '22 22:11

Carlo Moretti