猫鼬:检测插入的文档是否重复,如果重复,则返回现有文档 [英] mongoose: detect if document inserted is a duplicate and if so, return the existing document

查看:88
本文介绍了猫鼬:检测插入的文档是否重复,如果重复,则返回现有文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码:

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

    console.log(thisValue);

    thisValue.save(function(err, product, numberAffected) {
        if (err) {
            if (err.code === 11000) { //error for dupes
                console.error('Duplicate blocked!');
                models.Value.find({title:title}, function(err, docs)
                   {
                       callback(docs) //this is ugly
                   });
            }
            return;
        }

        console.log('Value saved:', product);
        if (callback) {
            callback(product);
        }
    });

如果我检测到要插入重复项,则将其阻止.但是,发生这种情况时,我想退回现有文档.如您所见,我实现了一系列回调,但这很丑陋且不可预测(即,我如何知道将调用哪个回调?如何传递正确的回调?).有谁知道如何解决这个问题?任何帮助表示赞赏.

If I detect that a duplicate is trying to be inserted, i block it. However, when that happens, i want to return the existing document. As you can see I have implemented a string of callbacks, but this is ugly and its unpredictable (ie. how do i know which callback will be called? How do i pass in the right one?). Does anyone know how to solve this problem? Any help appreciated.

推荐答案

虽然您的代码无法处理一些错误情况,并且使用了错误的find函数,但是一般流程却很典型,可以完成您想做的工作.

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. 如果有重复错误,则不会调用回调,这可能会导致NodeJs应用程序出现下游问题
  2. 使用 findOne 而不是find,因为只有给定密钥的结果是唯一的.否则,它将返回一个数组.
  3. 如果您的回调将传统的error作为第一个参数,则可以直接将回调传递给findOne函数,而不必引入匿名函数.
  4. 您可能还希望最终查看 findOneAndUpdate ,具体取决于您最终的模式和逻辑将是什么.
  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.

如前所述,您也许可以使用findOneAndUpdate,但需要支付额外费用.

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.

我已经对您的代码进行了一些清理...但是它确实非常简单,回调应该很清楚.函数的callback始终接收新保存的文档或与之匹配的副本.函数调用saveNewValue负责检查错误并正确处理.您将看到我如何确定无论错误类型如何都将调用该回调,并且始终以一致的方式调用该回调.

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);
    });
}

或者,您可以使用 promise 模式.此示例使用 when.js .

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
});

这篇关于猫鼬:检测插入的文档是否重复,如果重复,则返回现有文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆