我在我的Nodejs项目中使用Sequelize,我发现了一个问题,我很难解决。基本上我有一个cron从服务器获取一个对象数组,而不是将它作为对象插入我的数据库(对于这种情况,卡通)。但如果我已经拥有其中一个对象,我必须更新它。
基本上我有一个对象数组,可以使用BulkCreate()方法。但是当Cron再次启动时,它并没有解决它,因此我需要使用upsert true标志进行某种更新。主要问题:我必须有一个回调,在所有这些创建或更新之后只触发一次。有谁知道我该怎么做?迭代一个对象数组..创建或更新它然后获得一个回调?
感谢您的关注
从docs开始,一旦有了对象,就不需要查询where
来执行更新。此外,使用promise应简化回调:
履行
function upsert(values, condition) {
return Model
.findOne({ where: condition })
.then(function(obj) {
if(obj) { // update
return obj.update(values);
}
else { // insert
return Model.create(values);
}
})
}
用法
upsert({ first_name: 'Taku' }, { id: 1234 }).then(function(result){
res.status(200).send({success: true});
});
注意
这意味着建议重新考虑这种方法,并且可能只是在一次网络呼叫中更新值,并且:
你可以使用upsert它更容易。
实施细节:
- MySQL - 作为单个查询实现
INSERT values ON DUPLICATE KEY UPDATE values
- PostgreSQL - 作为临时函数实现,具有异常处理:
INSERT EXCEPTION WHEN unique_constraint UPDATE
- SQLite - 实现为两个查询
INSERT; UPDATE
。这意味着无论行是否已存在,都会执行更新- MSSQL - 使用
MERGE and WHEN (NOT) MATCHED THEN
作为单个查询实现请注意,无论行是创建还是更新,SQLite都会为已创建返回undefined。这是因为SQLite总是在单个查询中运行INSERT OR IGNORE + UPDATE
,因此无法知道是否插入了行。
立即使用async / await更新07/2019
async function updateOrCreate (model, where, newItem) {
// First try to find the record
const foundItem = await model.findOne({where});
if (!foundItem) {
// Item not found, create a new one
const item = await model.create(newItem)
return {item, created: true};
}
// Found an item, update it
const item = await model.update(newItem, {where});
return {item, created: false};
}
我喜欢Ataik的想法,但是它缩短了一点:
function updateOrCreate (model, where, newItem) {
// First try to find the record
return model
.findOne({where: where})
.then(function (foundItem) {
if (!foundItem) {
// Item not found, create a new one
return model
.create(newItem)
.then(function (item) { return {item: item, created: true}; })
}
// Found an item, update it
return model
.update(newItem, {where: where})
.then(function (item) { return {item: item, created: false} }) ;
}
}
用法:
updateOrCreate(models.NewsItem, {slug: 'sometitle1'}, {title: 'Hello World'})
.then(function(result) {
result.item; // the model
result.created; // bool, if a new item was created.
});
可选:在这里添加错误处理,但我强烈建议链接一个请求的所有promise,并在最后有一个错误处理程序。
updateOrCreate(models.NewsItem, {slug: 'sometitle1'}, {title: 'Hello World'})
.then(..)
.catch(function(err){});
这可能是个老问题,但这就是我所做的:
var updateOrCreate = function (model, where, newItem, onCreate, onUpdate, onError) {
// First try to find the record
model.findOne({where: where}).then(function (foundItem) {
if (!foundItem) {
// Item not found, create a new one
model.create(newItem)
.then(onCreate)
.catch(onError);
} else {
// Found an item, update it
model.update(newItem, {where: where})
.then(onUpdate)
.catch(onError);
;
}
}).catch(onError);
}
updateOrCreate(
models.NewsItem, {title: 'sometitle1'}, {title: 'sometitle'},
function () {
console.log('created');
},
function () {
console.log('updated');
},
console.log);
声音喜欢你想把你的Sequelize电话包在async.each中。
这可以使用自定义事件发射器完成。
假设您的数据位于名为data的变量中。
new Sequelize.Utils.CustomEventEmitter(function(emitter) {
if(data.id){
Model.update(data, {id: data.id })
.success(function(){
emitter.emit('success', data.id );
}).error(function(error){
emitter.emit('error', error );
});
} else {
Model.build(data).save().success(function(d){
emitter.emit('success', d.id );
}).error(function(error){
emitter.emit('error', error );
});
}
}).success(function(data_id){
// Your callback stuff here
}).error(function(error){
// error stuff here
}).run(); // kick off the queries
你可以在续集中使用findOrCreate
然后使用update
方法。这是一个带有async.js的示例
async.auto({
getInstance : function(cb) {
Model.findOrCreate({
attribute : value,
...
}).complete(function(err, result) {
if (err) {
cb(null, false);
} else {
cb(null, result);
}
});
},
updateInstance : ['getInstance', function(cb, result) {
if (!result || !result.getInstance) {
cb(null, false);
} else {
result.getInstance.updateAttributes({
attribute : value,
...
}, ['attribute', ...]).complete(function(err, result) {
if (err) {
cb(null, false);
} else {
cb(null, result);
}
});
}
}]
}, function(err, allResults) {
if (err || !allResults || !allResults.updateInstance) {
// job not done
} else {
// job done
});
});
这是一个简单的例子,可以更新deviceID - > pushToken映射或创建它:
var Promise = require('promise');
var PushToken = require("../models").PushToken;
var createOrUpdatePushToken = function (deviceID, pushToken) {
return new Promise(function (fulfill, reject) {
PushToken
.findOrCreate({
where: {
deviceID: deviceID
}, defaults: {
pushToken: pushToken
}
})
.spread(function (foundOrCreatedPushToken, created) {
if (created) {
fulfill(foundOrCreatedPushToken);
} else {
foundOrCreatedPushToken
.update({
pushToken: pushToken
})
.then(function (updatedPushToken) {
fulfill(updatedPushToken);
})
.catch(function (err) {
reject(err);
});
}
});
});
};