Knex.JS自动更新触发器
Knex.JS Auto Update Trigger
我正在使用Knex.JS迁移工具。但是,在创建表时,我希望有一个名为updated_at
的列,当数据库中的记录更新时,该列会自动更新。
例如,这里有一个表:
knex.schema.createTable('table_name', function(table) {
table.increments();
table.string('name');
table.timestamp("created_at").defaultTo(knex.fn.now());
table.timestamp("updated_at").defaultTo(knex.fn.now());
table.timestamp("deleted_at");
})
created_at
和updated_at
列默认为创建记录的时间,这很好。但是,当更新该记录时,我希望updated_at
列显示它自动更新的新时间。
我宁愿不写原始的postgres。
谢谢!
对于Postgres,您需要一个触发器。这是我成功使用的一种方法。
添加函数
如果您有多个按设置顺序的迁移文件,您可能需要人为地更改文件名中的日期戳,以使其首先运行(或者只将其添加到您的第一个迁移文件中)。如果无法回滚,则可能需要通过psql
手动执行此步骤。然而,对于新项目:
const ON_UPDATE_TIMESTAMP_FUNCTION = `
CREATE OR REPLACE FUNCTION on_update_timestamp()
RETURNS trigger AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
`
const DROP_ON_UPDATE_TIMESTAMP_FUNCTION = `DROP FUNCTION on_update_timestamp`
exports.up = knex => knex.raw(ON_UPDATE_TIMESTAMP_FUNCTION)
exports.down = knex => knex.raw(DROP_ON_UPDATE_TIMESTAMP_FUNCTION)
现在,该功能应该可用于所有后续迁移。
定义knex.raw
触发器帮助程序
如果可以避免的话,我发现在迁移文件中不重复大块的SQL更具表现力。我在这里使用了knexfile.js
,但如果你不想让它复杂化,你可以在任何地方定义它。
module.exports = {
development: {
// ...
},
production: {
// ...
},
onUpdateTrigger: table => `
CREATE TRIGGER ${table}_updated_at
BEFORE UPDATE ON ${table}
FOR EACH ROW
EXECUTE PROCEDURE on_update_timestamp();
`
}
使用辅助对象
最后,我们可以非常方便地定义自动更新触发器:
const { onUpdateTrigger } = require('../knexfile')
exports.up = knex =>
knex.schema.createTable('posts', t => {
t.increments()
t.string('title')
t.string('body')
t.timestamps(true, true)
})
.then(() => knex.raw(onUpdateTrigger('posts')))
exports.down = knex => knex.schema.dropTable('posts')
请注意,删除该表就足以消除触发器:我们不需要显式的DROP TRIGGER
。
这一切看起来可能需要做很多工作,但一旦你完成了,它就非常"设置并忘记",如果你想避免使用ORM,它也很方便。
您可以使用时间戳创建knex迁移:
exports.up = (knex, Promise) => {
return Promise.all([
knex.schema.createTable('table_name', (table) => {
table.increments();
table.string('name');
table.timestamps(false, true);
table.timestamp('deleted_at').defaultTo(knex.fn.now());
})
]);
};
exports.down = (knex, Promise) => {
return Promise.all([
knex.schema.dropTableIfExists('table_name')
]);
};
使用时间戳,将创建一个数据库模式,其中添加一个created_at
和updated_at
列,每个列都包含一个初始时间戳。
要使updated_at
列保持最新,您需要knex.raw
:
table.timestamp('updated_at').defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
要跳过knex.raw
解决方案,我建议使用像Objection.js这样的高级ORM。使用Objection.js,您可以实现自己的BaseModel
,然后更新updated_at
列:
Something.js
const BaseModel = require('./BaseModel');
class Something extends BaseModel {
constructor() {
super();
}
static get tableName() {
return 'table_name';
}
}
module.exports = Something;
基本模型
const knexfile = require('../../knexfile');
const knex = require('knex')(knexfile.development);
const Model = require('objection').Model;
class BaseModel extends Model {
$beforeUpdate() {
this.updated_at = knex.fn.now();
}
}
module.exports = BaseModel;
来源:http://vincit.github.io/objection.js/#timestamps
这是我在Mysql 5.6+中实现这一点的方法
我没有使用table.timestamps的原因是我使用了DATETIME而不是时间戳。
table.dateTime('created_on')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP'))
table.dateTime('updated_on')
.notNullable()
.defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
这不是Knex的特性。Knex只创建列,但不会为您更新它们。
但是,如果使用Bookshelf ORM,则可以指定表具有时间戳,并且它将设置&按预期更新列:
- 书架文档
- Github问题
exports.up=(knex)=>{返回knex.raw(create or replace function table_name_update() RETURNS trigger AS $$ begin new.updated_at = now(); RETURN NEW; end; $$ language 'plpgsql'; create or replace trigger tg_table_name_update on table_name before update for each row execute table_name_update();
)};
exports.down=(knex)=>{返回knex.raw(drop table if exists table_name; drop function if exists table_name_update;
)};
您可以直接使用此函数
table.timestamps()
这将在默认情况下创建"created_at"answers"updated_at"列,并相应地更新它们
https://knexjs.org/#Schema-时间戳
- Javascript循环不会自我更新
- 添加文字和评论功能更新Div
- AngularJS:ng之后,重复$scope值未按预期更新
- 如何通过数组更新角度子范围
- Ajax聊天消息重复而不仅仅是更新
- 通过CSV文件上载更新数据库表
- 平均值:无法将数据更新到数据库
- $rootScope未使用forEach进行更新
- 如何在更新面板内部调用/触发javascript函数<触发器>标签
- Knex.JS自动更新触发器
- 已选择:已更新触发器阻止文本在输入中呈现
- 当触发器按钮使用 jquery 和 ajax 时,无法更新会话
- 更新失败,无法加载触发器.错误为“未捕获” 您必须使用 Parse.initialize 指定密钥
- 界面,用户输入作为服务器端php和客户端更新的触发器
- 更新面板AsyncPostBack和PostBack触发器
- Alfresco更新动作触发器从添加内容链接
- 更新Mapbox地图上的页面滚动触发器
- ASP.. NET触发器更新面板_dopostback
- 我可以添加HTML按钮触发器更新面板
- AngularJS -当触发器变量在作用域中改变时,我的错误消息不会更新