简体   繁体   English

Knex.JS 自动更新触发器

[英]Knex.JS Auto Update Trigger

I am using Knex.JS migration tools.我正在使用Knex.JS迁移工具。 However, when creating a table, I'd like to have a column named updated_at that is automatically updated when a record is updated in the database.但是,在创建表时,我希望有一个名为updated_at的列,当数据库中的记录更新时,该列会自动更新。

For example, here is a table:例如,这是一张表:

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");
})

The created_at and updated_at column defaults to the time the record is created, which is fine. created_atupdated_at列默认为记录创建的时间,这很好。 But, when that record is updated, I'd like the updated_at column to show the new time that it was updated at automatically.但是,当该记录更新时,我希望updated_at列显示它自动更新的新时间。

I'd prefer not to write in raw postgres.我不想用原始的 postgres 写。

Thanks!谢谢!

With Postgres, you'll need a trigger .使用 Postgres,你需要一个trigger Here's a method I've used successfully.这是我成功使用的方法。

Add a function添加功能

If you have multiple migration files in a set order, you might need to artificially change the datestamp in the filename to get this to run first (or just add it to your first migration file).如果您有多个按设定顺序排列的迁移文件,您可能需要人为地更改文件名中的日期戳以使其首先运行(或者只是将其添加到您的第一个迁移文件中)。 If you can't roll back, you might need to do this step manually via psql .如果无法回滚,则可能需要通过psql手动执行此步骤。 However, for new projects:但是,对于新项目:

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)

Now the function should be available to all subsequent migrations.现在该功能应该可用于所有后续迁移。

Define a knex.raw trigger helper定义knex.raw触发器助手

I find it more expressive not to repeat large chunks of SQL in migration files if I can avoid it.如果可以避免的话,我发现不在迁移文件中重复大量 SQL 会更有表现力。 I've used knexfile.js here but if you don't like to complicate that, you could define it wherever.我在这里使用了knexfile.js但如果你不想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();
  `
}

Use the helper使用帮手

Finally, we can fairly conveniently define auto-updating triggers:最后,我们可以相当方便地定义自动更新触发器:

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')

Note that dropping the table is enough to get rid of the trigger: we don't need an explicit DROP TRIGGER .请注意,删除表足以摆脱触发器:我们不需要显式DROP TRIGGER

This all might seem like a lot of work, but it's pretty "set-and-forget" once you've done it and handy if you want to avoid using an ORM.这一切看起来似乎需要做很多工作,但是一旦你完成了它,它就非常“一劳永逸”,如果你想避免使用 ORM,它会很方便。

You can create a knex migration using timestamps :您可以使用时间戳创建 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')
  ]);
};

With timestamps a database schema will be created which adds a created_at and updated_at column, each containing an initial timestamp.使用时间戳将创建一个数据库模式,该模式添加一个created_atupdated_at列,每个列都包含一个初始时间戳。

To keep the updated_at column current, you'll need knex.raw :要保持updated_at列最新,您需要knex.raw

table.timestamp('updated_at').defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));

To skip the knex.raw solution, I suggest using a high level ORM like Objection.js .要跳过knex.raw解决方案,我建议使用像Objection.js这样的高级 ORM。 With Objection.js you could implement your own BaseModel which then updates the updated_at column:使用Objection.js,您可以实现自己的BaseModel ,然后更新updated_at列:

Something.js东西.js

const BaseModel = require('./BaseModel');

class Something extends BaseModel {
  constructor() {
    super();
  }

  static get tableName() {
    return 'table_name';
  }
}

module.exports = Something;

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;

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

This is not a feature of Knex.这不是 Knex 的功能。 Knex only creates the columns, but does not keep them up to date for you. Knex 仅创建列,但不会为您保持最新状态。

If you use, the Bookshelf ORM, however, you can specify that a table has timestamps, and it will set & update the columns as expected:但是,如果使用 Bookshelf ORM,则可以指定表具有时间戳,并且它将按预期设置和更新列:

This is my way of doing that in Mysql 5.6+这是我在 Mysql 5.6+ 中的做法

The reason I didn't use table.timestamps is because I use DATETIME instead of timestamp.我没有使用 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'))

exports.up = (knex) => { return 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.up = (knex) => { return 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) => { return knex.raw( drop table if exists table_name; drop function if exists table_name_update; ) }; exports.down = (knex) => { return knex.raw( drop table if exists table_name; drop function if exists table_name_update; ) };

You can directly use this function可以直接使用这个功能

table.timestamps()

This will create the 'created_at' and 'updated_at' columns by default and update them accordingly这将默认创建“created_at”和“updated_at”列并相应地更新它们

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM