Knex.JS自动更新触发器

aas*_*ah7 19 javascript postgresql knex.js

我正在使用Knex.JS迁移工具.但是,在创建表时,我希望updated_at在数据库中更新记录时,会自动更新一个名为column的列.

例如,这是一个表:

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");
})
Run Code Online (Sandbox Code Playgroud)

created_atupdated_at列默认为创建记录的时间,这是罚款.但是,当更新该记录时,我希望该updated_at列显示自动更新的新时间.

我宁愿不用原始的postgres写.

谢谢!

Ric*_*her 25

本尼的回答是完全正确的.但是,我注意到你特别提到了Postgres,在这种情况下,他的psql语法对你不起作用.这是我成功使用的方法.

添加功能

如果您按设定顺序拥有多个迁移文件,则可能需要人为地更改文件名中的日期戳以使其首先运行(或者只是将其添加到第一个迁移文件中).如果无法回滚,则可能需要手动执行此步骤knex.raw.但是,对于新项目:

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)
Run Code Online (Sandbox Code Playgroud)

现在,该功能应该可用于所有后续迁移.

定义knexfile.js触发器帮助器

我发现如果我可以避免在迁移文件中重复大块SQL,那就更有表现力了.我已经DROP TRIGGER在这里使用了,但是如果你不喜欢这样,你可以在任何地方定义它.

module.exports = {
  development: {
    // ...
  },

  production: {
    // ...
  },

  onUpdateTrigger: table => `
    CREATE TRIGGER ${table}_updated_at
    BEFORE UPDATE ON ${table}
    FOR EACH ROW
    EXECUTE PROCEDURE on_update_timestamp();
  `
}
Run Code Online (Sandbox Code Playgroud)

使用帮助器

最后,我们可以相当方便地定义自动更新触发器:

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')
Run Code Online (Sandbox Code Playgroud)

请注意,删除表足以摆脱触发器:我们不需要显式psql.

这一切似乎都是很多工作,但是如果您想要避免使用ORM,那么一旦完成它就会非常"一劳永逸".

  • 真棒的答案! (3认同)
  • 它不仅有效,而且是关于如何向 postgres 添加函数的绝佳示例。谢谢! (2认同)
  • 这是一个非常棒的解决方案,而且它很干净。谢谢,里奇! (2认同)

Ben*_*uer 7

您可以使用时间戳创建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')
  ]);
};
Run Code Online (Sandbox Code Playgroud)

使用时间戳,将创建一个数据库模式,该模式添加一个created_atupdated_at列,每个包含一个初始时间戳.

要使updated_at列保持最新,您需要knex.raw:

table.timestamp('updated_at').defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
Run Code Online (Sandbox Code Playgroud)

为了跳过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;
Run Code Online (Sandbox Code Playgroud)

BaseModel

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;
Run Code Online (Sandbox Code Playgroud)

资料来源:http://vincit.github.io/objection.js/#timestamps

  • 支持 Objection.js。对于 Node.js 来说非常好的 ORM (3认同)

小智 -4

可以直接使用这个功能

table.timestamps()
Run Code Online (Sandbox Code Playgroud)

这将默认创建“created_at”和“updated_at”列并相应地更新它们

https://knexjs.org/#Schema-timestamps

  • 即使使用了“table.timestamps(false, true);”,它也不会更新“updated_at”列。 (13认同)
  • `table.timestamps()` 需要变成 `table.timestamps(false, true);` 以保证在没有给出数据时使用当前时间戳。 (5认同)