mongoose: detect if document inserted is a duplicate and if so, return the existing document

后端 未结 2 709
感情败类
感情败类 2021-02-13 13:47

This is my code:

    var thisValue = new models.Value({
        id:id,
        title:title //this is a unique value
    });

    console.log(thisValue);

    thi         


        
2条回答
  •  走了就别回头了
    2021-02-13 14:08

    While your code doesn't handle a few error cases, and uses the wrong find function, the general flow is typical giving the work you want to do.

    1. If there are errors other than the duplicate, the callback isn't called, which likely will cause downstream issues in your NodeJs application
    2. use findOne rather than find as there will be only one result given the key is unique. Otherwise, it will return an array.
    3. If your callback expected the traditional error as the first argument, you could directly pass the callback to the findOne function rather than introducing an anonymous function.
    4. You also might want to look at findOneAndUpdate eventually, depending on what your final schema and logic will be.

    As mentioned, you might be able to use findOneAndUpdate, but with additional cost.

    function save(id, title, callback) {
        Value.findOneAndUpdate(
           {id: id, title: title}, /* query */
           {id: id, title: title}, /* update */
           { upsert: true}, /* create if it doesn't exist */
           callback);
    }
    

    There's still a callback of course, but it will write the data again if the duplicate is found. Whether that's an issue is really dependent on use cases.

    I've done a little clean-up of your code... but it's really quite simple and the callback should be clear. The callback to the function always receives either the newly saved document or the one that was matched as a duplicate. It's the responsibility of the function calling saveNewValue to check for an error and properly handle it. You'll see how I've also made certain that the callback is called regardless of type of error and is always called with the result in a consistent way.

    function saveNewValue(id, title, callback) {
        if (!callback) { throw new Error("callback required"); }
        var thisValue = new models.Value({
            id:id,
            title:title //this is a unique value
        });
    
        thisValue.save(function(err, product) {
            if (err) {
                if (err.code === 11000) { //error for dupes
                    return models.Value.findOne({title:title}, callback);
                }            
            }    
            callback(err, product);
        });
    }
    

    Alternatively, you could use the promise pattern. This example is using when.js.

    var when = require('when');
    
    function saveNewValue(id, title) {
        var deferred = when.defer();
    
        var thisValue = new models.Value({
            id:id,
            title:title //this is a unique value
        });
    
        thisValue.save(function(err, product) {
            if (err) {
                if (err.code === 11000) { //error for dupes
                    return models.Value.findOne({title:title}, function(err, val) {
                        if (err) {
                            return deferred.reject(err);
                        }
                        return deferred.resolve(val);
                    });
                }
                return deferred.reject(err);
            }
            return deferred.resolve(product);
        });
    
        return deferred.promise;
    }
    
    saveNewValue('123', 'my title').then(function(doc) {
        // success
    }, function(err) {
        // failure
    });
    

提交回复
热议问题