Automatically Trigger Knex.JS Updates

Utilizing the migration tools provided by Knex.JS, I am attempting to create a table with an automatically updating column named updated_at whenever a record is modified in the database.

Take, for instance, this 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");
})

While the created_at and updated_at columns are set to the time of creation by default, I desire the latter to reflect the latest update timestamp automatically.

I would rather evade using raw postgres SQL statements if possible.

Appreciate any guidance!

Answer №1

To implement auto-updating timestamps in Postgres, you can utilize a trigger. Below is an effective method that I have successfully used:

Step 1: Add a Function

If you have multiple migration files and need to ensure a specific order, you may have to adjust the datestamp in the filename or include it in the first migration file. For new projects, follow these steps:

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)

This function will now be available for all future migrations.

Step 2: Define a knex.raw Trigger Helper

To keep your migration files clean, define a helper function using knexfile.js or any preferred location:

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

  production: {
    // ...
  },

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

Step 3: Implement the Auto-Update Trigger

Easily set up auto-updating triggers with the following code snippet:

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

Simply dropping the table will remove the trigger without needing a separate DROP TRIGGER command.

Although this setup may appear extensive, it becomes a seamless process once implemented, offering a non-ORM solution for automatic timestamp updates.

Answer №2

When creating a knex migration, you can utilize the timestamps feature:

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')
  ]);
};

Using timestamps will add a created_at and updated_at column to your database schema with initial timestamps.

To automatically update the updated_at column, you can use knex.raw:

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

If you prefer not to use knex.raw, consider using a high-level ORM like Objection.js. With Objection.js, you can create a custom BaseModel to handle updating the updated_at column:

Something.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:

Answer №3

Here is the way I prefer to handle this in MySQL version 5.6 and above.

I decided not to use table.timestamps because I opted for DATETIME over timestamp data type.

table.dateTime('created_at')
        .notNullable()
        .defaultTo(knex.raw('CURRENT_TIMESTAMP'))

table.dateTime('updated_at')
        .notNullable()
        .defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))

Answer №4

Let's create a new function in our database using Knex:

To update the table "table_name", we will define a PL/pgSQL function called "table_name_update". This function sets the column "updated_at" to the current timestamp whenever a row is updated. We will then create a trigger named "tg_table_name_update" that executes the "table_name_update" function before each update on the "table_name" table.

For reverting this migration, we simply drop the table and the function if they exist:

Answer №5

In Knex, the feature of automatically updating columns is not available. Knex focuses on creating columns rather than maintaining them for you.

However, if you choose to use the Bookshelf ORM, you have the option to designate that a table should have timestamps. This will ensure that the columns are set and updated as needed:

Answer №6

Feel free to utilize this method

table.timestamp()

By doing so, you will automatically generate the 'created_at' and 'updated_at' columns and keep them up-to-date

Visit here for more information on timestamp handling in Knex.js

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to create a blurred effect on an image during loading, and then transition to a sharp image once it is fully loaded?

I'm currently working on a project where I want the images to display as a blurred preview initially, and then become clear once fully loaded. This is similar to the feature seen on Instagram, where the app shows a blurred image before displaying the ...

django, the X-CSRFToken in the request header is improperly configured

Essentially, I have managed to successfully send a CSRF token to the frontend and store it in the cookie section of the application tab within the developer console of the browser with this code: @method_decorator(ensure_csrf_cookie) def get(self, ...

Is there a way to access the state value within the reducer function of createSlice?

Currently, I am utilizing redux-toolkit within my react project. A concern arises in a specific reducer inside the createSlice method where I aim to incorporate an existing array of entities from the state and then merge it with a new array before finalizi ...

JavaScript code to find a date within a specified range

I have developed a script that calculates the number of weeks between two specified dates. It then generates a table where the number of rows equals the number of weeks. The script can be viewed on JSFIDDLE Script: $('#test').click(function ...

Understanding the getJSON MethodExplaining how

$.getJSON( main_url + "tasks/", { "task":8, "last":lastMsgID } I'm a bit confused about how this code functions. I'm looking for a way to retrieve messages from a shoutbox using a URL or some sort of method that the function here ...

Discovering the current time and start time of today in EST can be achieved by utilizing Moment.js

Need help with creating Start and End Time stamps using Moment.js in EST: Start Time should reflect the beginning of today End Time should show the current time. This is how I have implemented it using moment.js: var time = new Date(); var startTime=D ...

Tips for safeguarding AJAX or javascript-based web applications

Utilizing AJAX, this function retrieves information about an image in the database with the ID of 219 when a button is clicked. Any visitor to this webpage has the ability to alter the JavaScript code by inspecting the source code. By modifying the code a ...

Ways to position loading animation in the center and create a lightbox effect for the rest of the page

I have implemented a custom loader in CSS with the following styles: .loader { border: 16px solid #f3f3f3; /* Light grey */ border-top: 16px solid #3498db; /* Blue */ border-radius: 50%; width: 80px; height: 80px; animation: spin 2s linear inf ...

What is the best way to extract parameters from a JSON object?

Here is the complete code: $.post('test.php', { id: id },function (data) { console.log(data); var Server = data.response.server; var Photo = data.response.photo; console.log(Server); console.log(Photo); }); When I receive data I get JSON data ...

Identifying the presence of a particular cookie

I'm currently working on a project that already has several cookies stored. My goal is to determine if the cookie labeled "login" exists. Below is the code snippet I am using: if (document.cookie.indexOf("login") >= 0) { alert("login cookie ex ...

Having difficulty personalizing the email template on AWS SES

I am currently working on setting up a forgot password email system using AWS SES. Below is the template I have created: { "Template":{ "TemplateName": "forgotpasswrd", "SubjectPart": "Forgot ...

Express Module Paths Failing to Function Properly

When I first started building my routes, I had everything in one api.js file. However, I realized there might be a better approach, so I did some research online to see how others handle it. After following a few tutorials, I decided on a new layout with s ...

Updating an array element in Mongoose, the MongoDB ORM

I am currently in the process of making changes to a MongoDb collection that contains an array of documents called items. To achieve this, I am utilizing the express and mongoose frameworks. This is how my schema is structured: const mongoose = require(" ...

What is the best way to retrieve information from a data set?

After borrowing some basic HTML, CSS, and JavaScript code from CodePen, I ran into an issue while attempting to convert it to React. The error message says that it cannot read properties of null (specifically 'dataset'). Here is the JavaScript c ...

Utilizing Immutable.js within React's Pure Components

Having some difficulty incorporating React PureComponents with Immutable.js. Take a look at this demonstration: https://codepen.io/SandoCalrissian/pen/QaEmeX The demo showcases 2 components being rendered. The first (NoramlPure) is a regular PureComponen ...

Update DataTable 1.9 while preserving existing rows

I'm currently using dataTables js version 1.9 Periodically, an ajax call is made to the server to retrieve information that should be displayed in a table every 60 seconds or so. Although I can easily clear and repopulate the table like this: $(id) ...

What sets apart getStaticProps + fallback:true from getServerSideProps?

I have gone through the Next.js documentation multiple times, but I am still struggling to grasp the difference between using getStaticProps with fallback:true and getServerSideProps. From my understanding: getStaticProps getStaticProps is rendered at b ...

Issue with Masonry layout not adjusting to change in window size

Something seems to be fixed on displaying four rows, no matter the size of the window. Previously, it would adjust to three rows or fewer as the browser was resized. I recently played around with columnWidth, but reverting it back to 250 doesn't seem ...

Enabling the execution of returned scripts using JQuery AJAX

I have a hyperlink that I need to send a DELETE request using JQuery through AJAX. if(confirm("Do you wish to proceed?")) { $.ajax({ url: $(this).attr("href"), type: 'DELETE', success: function(result) { // Perform act ...

What could be causing my Chrome extension to function on Mac but not on a PC?

I created a basic Chrome extension that includes a background page with the following code: <script type="text/javascript> chrome.tabs.onDetached.addListener(function(tabId, info){ var id = tabId; chrome.tabs.get(id, function(tab) { ...