【问题标题】:Sequelize How do you format date to YYYY-MM-DD HH:mm:ss and keep the columns as snake case续集如何将日期格式化为 YYYY-MM-DD HH:mm:ss 并将列保持为蛇形
【发布时间】:2021-12-15 08:59:44
【问题描述】:

您好,我正在使用带有 Postgres 数据库的 Sequelize

所以我试图将续集 createdAt 和 updatedAt 列上的日期格式化为YYYY-MM-DD HH:mm:ss 以及将列保持为snake_case 而不是camelcase 所以它们将是created_atupdated_at我怎样才能做到这一点?我尝试了以下方法:

    createdAt: {
      type: DataTypes.DATE,
      allowNull: false,
      defaultValue: moment.utc().format('YYYY-MM-DD HH:mm:ss'),
      field: 'created_at'
    },

    createdAt: {
      type: DataTypes.DATE,
      defaultValue: sequelize.NOW,
      set(value) {
        return value.toISOString().replace(/\..+/g, '')
// coming in the db as 2021-10-31 01:34:48.81+00 so wanted to remove evrything after the dot
      },
      name: 'createdAt',
      field: 'created_at',
    },

不工作,我收到此错误

          throw new Error(`Value for "${key}" option must be a string or a boolean, got ${typeof this.options[key]}`);
          ^

Error: Value for "createdAt" option must be a string or a boolean, got object

这是上面定义的整个表格,我已经确定了我需要帮助的地方

  const Supplier = sequelize.define('Supplier', {
    id: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      allowNull: false,
      primaryKey: true
    },
    name: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
      validate: {
        len: [1, 50]
      }
    },
    description: {
      type: DataTypes.STRING,
      allowNull: true,
    },
  }, {
    tableName: 'suppliers',
    timestamps: true,
    createdAt: {
      type: DataTypes.DATE,
      defaultValue: sequelize.NOW,
      set(value) {
        return value.toISOString().replace(/\..+/g, '')
      },
      name: 'createdAt',
      field: 'created_at',
    },
    updatedAt: {
      type: DataTypes.DATE,
      defaultValue: sequelize.NOW,
      set(value) {
        return value.toISOString().replace(/\..+/g, '')
      },
      field: 'updated_at',
    },
    // freezeTableName: true
    // paranoid: true
  });

谢谢

Today Sequelize docs is not working here is a webarchive's for it

https://web.archive.org/web/20200731154157/http://sequelize.org/master/index.html

【问题讨论】:

  • 错误说 createdAt 需要一个字符串或一个布尔值,并且代码看起来像是分配了一个对象createdAt: {...}
  • 我如何才能具体将其设为字符串并格式化为YYYY-MM-DD HH:mm:ss 并将列保持为蛇形。例如,我知道如果我这样做了:createdAt: 'created_at',,如他们的文档中所述,我将列设置为蛇形案例,所以我的另一个目标是格式化它,正如我所说的那样,数据库中没有毫秒,我该怎么做? @danh
  • 我刚刚在“get()”方法中进行了一些编辑,以获得您想要的确切格式,所以它现在准备好了。如果您将在您的问题下添加“postgres”标签以及此处需要“日期”类型,那将是很好的。

标签: javascript node.js postgresql date sequelize.js


【解决方案1】:

解决方案

至于上面的get() 方法只会将格式化的值返回给客户端,但它不会将其保存到数据库中。我找到了三个选项将其保存到数据库中为遇到类似情况的人提供此问题的解决方案。

1.第一个选项

node_modules/sequelize/lib/data-types.js

里面

我们要修改下面的代码

DATE.prototype._stringify = function _stringify(date, options) {
  date = this._applyTimezone(date, options);

  // Z here means current timezone, _not_ UTC
  // return date.format('YYYY-MM-DD HH:mm:ss.SSS Z');// from this to the below code
  return date.format('YYYY-MM-DD HH:mm:ss.SSS'); // to this
};

2。第二种选择

如果您不触摸您的 node_modules 文件夹并且不喜欢选项 1,那么更好的解决方案是执行您在选项 1 中所做的操作,但在您自己的 db.js 文件中:

const { Sequelize } = require('sequelize');
const { DB } = require('../config');

// Override timezone formatting by requiring the Sequelize and doing it here instead
Sequelize.DATE.prototype._stringify = function _stringify(date, options) {
  date = this._applyTimezone(date, options);

  // Z here means current timezone, _not_ UTC
  // return date.format('YYYY-MM-DD HH:mm:ss.SSS Z');
  return date.format('YYYY-MM-DD HH:mm:ss Z');
};

const db = new Sequelize(`${DB.DIALECT}://${DB.USER}:${DB.PASS}@${DB.HOST}:${DB.PORT}/${DB.DB}`, {
  logging: false
})

module.exports = db;

所以这两个选项更像是全局方式,因此格式将适用于您的所有模型。

3.第三个选项

最后的选择是使用钩子为每个模型做这件事

例子:

const Supplier = sequelize.define('Supplier', {
// col attributes 
}, {
    tableName: 'suppliers',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at',
    hooks : {
      beforeCreate : (record, options) => {
          record.dataValues.created_at = new Date().toISOString().replace(/T/, ' ').replace(/\..+/g, '');
          record.dataValues.updated_at = new Date().toISOString().replace(/T/, ' ').replace(/\..+/g, '');
      },
      beforeUpdate : (record, options) => {
          record.dataValues.updated_at = new Date().toISOString().replace(/T/, ' ').replace(/\..+/g, '');
      }
    },
})

【讨论】:

  • 我的想法:我不能说这件事的好坏,但如果您知道这些解决方案会如何影响您的应用程序的未来开发/性能,那就太好了。附言无论如何,选择是你的;)
  • 1.如果你想在核心包中进行更改,你不必更改 node_modules 中的任何内容(你知道这有多糟糕)
  • 2.如果您在“DATE.prototype._stringify”中进行更改,您必须知道它会影响您的整个应用程序,并且您将来不能像以前那样使用 DATE 类型(对于 1-st 相同),如果这不是问题对你来说,那么这可能对你有用。
  • 3.请记住,续集“钩子”的工作速度会有点慢,因为您使用了正则表达式替换(不推荐正则表达式操作,但仅适用于关键情况,因此请尽量避免使用它们)和“beforeCreate”/“beforeUpdate”将处理每个保存/编辑数据库请求,并且会以某种方式减慢该过程。
  • 感谢您的提问,我也探索了很多东西 ;)
【解决方案2】:

据我了解,您的问题包含一些子问题:

  • 序列化表列下划线的名称;
  • 续集日期格式;
  • 不使用moment;

这是我刚刚得到的一些工作示例(具有上述要求):

像这样进行后续迁移:

'use strict';

module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.createTable('items', {
            // ...
            created_at: {
                allowNull: false,
                type: Sequelize.DATE
            },
            // ...
        });
    },
    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable('items');
    }
};

有这样的续集模型:

'use strict';

// WITH moment
// const moment = require('moment');

module.exports = (sequelize, DataTypes) => {
    // const now = new Date();
    return sequelize.define('Item', {
        // ...
        created_at: {
            allowNull: false,
            // defaultValue: now,
            type: DataTypes.DATE,
            get() {
                // 1. WITHOUT moment
                const date = new Date(`${this.dataValues.created_at}`);
                return `${date.toISOString().split('T')[0]} ${date.toLocaleTimeString([], {month: '2-digit', timeStyle: 'medium', hour12: false})}`;
                
                // 2. WITHOUT moment (another solution)
                // const parts = date.toISOString().split('T');
                // return `${parts[0]} ${parts[1].substring(0, 8)}`;
                
                // 3. WITH moment
                // return moment(this.dataValues.created_at).format('D MM YYYY HH:mm:ss'); // 'D MMM YYYY, LT'
            }
        },
        // ...
    }, {
        tableName: 'items',
        freezeTableName: true,
        // underscored: true,
        timestamps: false,
        charset: 'utf8',
        collate: 'utf8_general_ci'
    });
};

不要忘记根据需要重命名表名,这里是“items”。

似乎有一个带有“下划线”属性的issue posted on github。无论如何它对我有用,因为其他属性有一个小技巧,所以就这样做,我相信它应该可以工作(我的 Sequelize 版本是“^5.22.3”)。

我使用过的来源:

如果需要,可以随意编辑和优化(我在 get() 方法中做了一些小的编辑,以获得所需的确切格式,无论如何我更喜欢使用 moment 作为列访问器)。

【讨论】:

  • 谢谢,但 get() 方法仍然只能让您看到格式化为 YYYY-MM-DD HH:mm:ss 的日期,但它不会以这种格式保存到数据库本身。正如 sequelize 文档中所说,get 方法仅在控制台上显示,但不会将其保存到数据库中。所以我想将格式保存到数据库中我正在尝试使用 set 方法,但我没有任何运气web.archive.org/web/20200730080051/http://sequelize.org/master/…
  • 看来,it's a known issue in Sequelize。你有两个解决方案 1. 实际上你不需要将日期保留在 "yyyy-mm-dd hh:mm:ss" 格式的列中,它无论如何都会将部分添加到右侧(你可以只使用-默认或自定义的getter,它不会出现在你的应用程序的任何地方,它只是保持这样); 2. 或者,如果你想要那样的话,你可以使用一些额外的技巧,比如this
  • 例如在我的应用程序中,我使用了这两种类型(DATEONLY 和 DATE),例如 this,它并没有阻止我按照自己的意愿进行格式化
  • 谢谢先生的帮助。我现在已经花时间查看您发送给我的那些链接。我喜欢这个解决方案github.com/sequelize/sequelize/issues/7879,由用户提供:dlredden from 16 sep 2017 .. Sequelize 早就应该对这个问题进行排序,而不是让我们从 node_modules 文件中更改某些内容。但是用户 dlredden 在 github 问题链接上的解决方案非常酷。我们不是直接接触 node_modules,而是要求它并应用我们自己的修改。
  • 我发现另一个解决方案是使用像这样的钩子github.com/sequelize/sequelize/issues/13613
猜你喜欢
  • 2013-11-01
  • 2015-11-03
  • 1970-01-01
  • 2020-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
相关资源
最近更新 更多