创建或更新 Sequelize
Posted
技术标签:
【中文标题】创建或更新 Sequelize【英文标题】:Create or Update Sequelize 【发布时间】:2013-08-20 16:49:38 【问题描述】:我在我的 Nodejs 项目中使用 Sequelize,我发现了一个我很难解决的问题。 基本上我有一个 cron 从服务器获取对象数组,然后将其作为对象插入到我的数据库中(对于这种情况,卡通)。但如果我已经拥有其中一个对象,我必须对其进行更新。
基本上我有一个对象数组,并且可以使用 BulkCreate() 方法。但是当 Cron 再次启动时,它并没有解决它,所以我需要一些带有 upsert true 标志的更新。主要问题是:在所有这些创建或更新之后,我必须有一个只触发一次的回调。有谁知道我该怎么做?迭代一个对象数组..创建或更新它,然后得到一个回调?
感谢关注
【问题讨论】:
【参考方案1】:从docs 获取对象后,您无需查询where
即可执行更新。此外,promise 的使用应该简化回调:
实施
function upsert(values, condition)
return Model
.findOne( where: condition )
.then(function(obj)
// update
if(obj)
return obj.update(values);
// insert
return Model.create(values);
)
用法
upsert( first_name: 'Taku' , id: 1234 ).then(function(result)
res.status(200).send(success: true);
);
注意
-
此操作不是原子操作。
创建 2 个网络调用。
这意味着建议重新考虑该方法,并且可能只更新一次网络调用中的值,或者:
-
查看返回的值(即 rows_affected)并决定做什么。
如果更新操作成功则返回成功。这是因为资源是否存在不在此服务的职责范围内。
【讨论】:
返回 Model.create(...values, ...condition) 处理高频数据时,非原子性会导致数据重复发生!否则,一个优雅的解决方案!【参考方案2】:您可以使用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 返回未定义的创建,没有 无论该行是创建还是更新。这是因为 SQLite 总是在一个查询中运行INSERT OR IGNORE + UPDATE
,所以有 无法知道该行是否已插入。
【讨论】:
使用 upsert,但如果它执行了插入,那么您需要获取插入的对象 :( - ***.com/a/29071422/48348 @IanGrainger - 不再! ***.com/a/50301416/107277【参考方案3】:更新 07/2019 现在使用 async/await
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.
);
可选:在此处添加错误处理,但我强烈建议将一个请求的所有承诺链接起来,并在最后使用一个错误处理程序。
updateOrCreate(models.NewsItem, slug: 'sometitle1', title: 'Hello World')
.then(..)
.catch(function(err));
【讨论】:
评论:我注意到 taht update() .. 不返回数据库对象。所以如果你需要它,你可以再拿一次。【参考方案4】:这可能是一个老问题,但这就是我所做的:
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);
【讨论】:
提示:使用承诺链进行错误处理并节省 50% 的代码 :) 父子关系怎么用?如何更新子表?【参考方案5】:User.upsert( a: 'a', b: 'b', username: 'john' )
它将尝试通过第一个参数中的哈希查找记录以更新它,如果找不到 - 然后将创建新记录
Here 是 sequelize 测试中的使用示例
it('works with upsert on id', function()
return this.User.upsert( id: 42, username: 'john' ).then(created =>
if (dialect === 'sqlite')
expect(created).to.be.undefined;
else
expect(created).to.be.ok;
this.clock.tick(1000);
return this.User.upsert( id: 42, username: 'doe' );
).then(created =>
if (dialect === 'sqlite')
expect(created).to.be.undefined;
else
expect(created).not.to.be.ok;
return this.User.findByPk(42);
).then(user =>
expect(user.createdAt).to.be.ok;
expect(user.username).to.equal('doe');
expect(user.updatedAt).to.be.afterTime(user.createdAt);
);
);
【讨论】:
它将在唯一或主键列上找到匹配项 我真的很喜欢回答问题的方式。荣誉【参考方案6】:听起来您想将 Sequelize 调用包装在 async.each 中。
【讨论】:
我希望在 Sequelize 的更新中提供一些令人不安的选项,但它似乎超出了路线图。我会试试这个。谢谢!【参考方案7】:这可以通过自定义事件发射器来完成。
假设您的数据位于名为 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
【讨论】:
【参考方案8】:您可以在 sequelize 中使用 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
);
);
【讨论】:
【参考方案9】:这是一个简单的例子,它要么更新 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);
);
);
);
;
【讨论】:
以上是关于创建或更新 Sequelize的主要内容,如果未能解决你的问题,请参考以下文章
我应该使用 POST 还是 PUT 进行可以创建或更新的 API 调用