猫鼬:检测插入的文档是否重复,如果重复,则返回现有文档 [英] mongoose: detect if document inserted is a duplicate and if so, return the existing document
问题描述
这是我的代码:
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.
- 如果有重复错误,则不会调用回调,这可能会导致NodeJs应用程序出现下游问题
- 使用
findOne
而不是find
,因为只有给定密钥的结果是唯一的.否则,它将返回一个数组. - 如果您的回调将传统的
error
作为第一个参数,则可以直接将回调传递给findOne
函数,而不必引入匿名函数. - 您可能还希望最终查看
findOneAndUpdate
,具体取决于您最终的模式和逻辑将是什么.
- If there are errors other than the duplicate, the callback isn't called, which likely will cause downstream issues in your NodeJs application
- use
findOne
rather thanfind
as there will be only one result given the key is unique. Otherwise, it will return an array. - If your callback expected the traditional
error
as the first argument, you could directly pass the callback to thefindOne
function rather than introducing an anonymous function. - 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屋!