sequelize.js - sequelize(和 sequelize-cli)queryInterface.createTable 在 PostgreSQL 上,PK id 类型为 UUID,defaultValue : Sequelize. DataTypes.UUIDV4 失败

标签 sequelize.js

是否使用在 postgreSQL 方言中自动生成的 UUID 类型 ID 支持 Sequelize ?
对生成的 CREATE TABLE sql 感到非常惊讶,这对于 postgreSQL 方言似乎不正确。
sequelize queryInterface.createTable via queryGenerator.createTableQuery on PostgreSQL with PK id of type UUID with defaultValue: Sequelize.DataTypes.UUIDV4 似乎没有创建正确的 CREATE TABLE,当没有提供 id 值时,它将为 id 创建默认 UUID 值。
下面调用 queryInterface.createTable

await queryInterface.createTable(
  // 'tableName'
  'User2s', 
  // 'attributes'
  {
    id: {
      allowNull: false,
//    autoIncrement: true,  // with this "npx sequelize-cli db:migrate" fails with 'ERROR syntax error at or near "SERIAL"' for type UUID. So not using this. This would work if id type was INTEGER (without setting 'defaultValue')
      defaultValue: Sequelize.UUIDV4,  
//    defaultValue: Sequelize.DataTypes.UUIDV4,  // tried this instead of above too
//    defaultValue: require('sequelize').UUIDV4, // tried this instead of above too
      primaryKey: true,
      type: Sequelize.UUID
    },
    firstName: {
      type: Sequelize.STRING
    },
    lastName: {
      type: Sequelize.STRING
    },
    email: {
      type: Sequelize.STRING
    },
    createdAt: {
      allowNull: false,
      type: Sequelize.DATE
    },
    updatedAt: {
      allowNull: false,
      type: Sequelize.DATE
    }
  },
  // 'options'
  {schema: process.env.DB_POSTGRESQL_SCHEMA_NAME}
);
在 SQL 下创建(方言设置为 postgreSQL);
CREATE TABLE exp15c."User2s"
(
    id uuid NOT NULL,
    "firstName" character varying(255) COLLATE pg_catalog."default",
    "lastName" character varying(255) COLLATE pg_catalog."default",
    email character varying(255) COLLATE pg_catalog."default",
    "createdAt" timestamp with time zone NOT NULL,
    "updatedAt" timestamp with time zone NOT NULL,
    CONSTRAINT "User2s_pkey" PRIMARY KEY (id)
)
但上面为 postgreSQL 生成的 CREATE TABLE 可能应该是;
CREATE TABLE exp15c."User2s"
(
    id uuid DEFAULT uuid_generate_v4(),
    "firstName" character varying(255) COLLATE pg_catalog."default",
    "lastName" character varying(255) COLLATE pg_catalog."default",
    email character varying(255) COLLATE pg_catalog."default",
    "createdAt" timestamp with time zone NOT NULL,
    "updatedAt" timestamp with time zone NOT NULL,
    CONSTRAINT "User2s_pkey" PRIMARY KEY (id)
)
当我看文件时;
https://github.com/sequelize/sequelize/blob/9f950cbcbdd659d559496b77c40e0f827b108561/docs/manual/core-concepts/model-basics.md
UUID
对于 UUID,请使用 DataTypes.UUID。它成为 PostgreSQL 和 SQLite 的 UUID 数据类型,以及 MySQL 的 CHAR(36) 数据类型。 Sequelize 可以为这些字段自动生成 UUID,只需使用 Sequelize.UUIDV1 或 Sequelize.UUIDV4 作为默认值:
{
  type: DataTypes.UUID,
  defaultValue: Sequelize.UUIDV4 // Or Sequelize.UUIDV1
}
它基本上说,我的上述用法是正确的。
当我查看 sequelize 源代码时,我看到了;
https://github.com/sequelize/sequelize/blob/9f950cbcbdd659d559496b77c40e0f827b108561/lib/utils.js
const uuidv4 = require('uuid').v4;
function toDefaultValue(value, dialect) {
  if (typeof value === 'function') {
    const tmp = value();
    if (tmp instanceof DataTypes.ABSTRACT) {
      return tmp.toSql();
    }
    return tmp;
  }
  if (value instanceof DataTypes.UUIDV1) {
    return uuidv1();
  }
  if (value instanceof DataTypes.UUIDV4) {
    return uuidv4();
  }
  if (value instanceof DataTypes.NOW) {
    return now(dialect);
  }
  if (Array.isArray(value)) {
    return value.slice();
  }
  if (_.isPlainObject(value)) {
    return { ...value };
  }
  return value;
}
exports.toDefaultValue = toDefaultValue;
以上方法用于
https://github.com/sequelize/sequelize/blob/9f950cbcbdd659d559496b77c40e0f827b108561/lib/model.js
_initValues(值,选项){
但不确定它是否真的适用于我的用例。
上面生成的 CREATE TABLE sql 执行并创建表,但是当我们尝试在没有 id 值的情况下插入时将不起作用,这就是我想要做的。
非常详细;
我正在通过如下 sequelize-cli 命令使用 sequelize;
0) 确保您的 postgreSQL 数据库具有新模式 'exp15c'
初始化 sequelize 目录和文件
npx sequelize-cli 初始化
  • 创建模型和迁移
    npx sequelize-cli model:generate --name User2 --attributes firstName:string,lastName:string,email:string
    将模型创建为;
    '使用严格';
    常量 {
    模型
    } = 要求(' Sequelize ');
    module.exports = (sequelize, DataTypes) => {
    类 User2 扩展模型 {
    静态关联(模型){
    //这里定义关联
    }
    };
    用户2.init({
    名字:DataTypes.STRING,
    姓氏:DataTypes.STRING,
    电子邮件:DataTypes.STRING
    }, {
    Sequelize ,
    模型名称:'用户2',
    });
    返回用户2;
    }
  • 手动更新生成的迁移文件以在“up”中包含上述代码
    '使用严格';
    模块.exports = {
    向上:异步(queryInterface,Sequelize)=> {
    //上面提供的带有“await queryInterface._createTable(”的代码片段在这里 },
    下来:异步(queryInterface,Sequelize)=> {
    等待 queryInterface.dropTable('User2s');
    }
    };
  • 执行上述迁移
    npx sequelize-cli 数据库:迁移
    观察它使用上面的 CREATE TABLE sql 创建了 User2s 表
  • 为 User2 创建“种子”文件
    npx sequelize-cli 种子:生成 --name init-user2
  • 手动将上面创建的 User2 种子更新为(注意没有指定 id 值,因为它是通过默认机制自动分配的);
    '使用严格';
    模块.exports = {
    向上:异步(queryInterface,Sequelize)=> {
    等待 queryInterface.bulkInsert(
    {tableName:'User2s',架构:'exp15c'},
    [
    {名:'ilker',姓:'kiris',电子邮件:'ilker@gmail.com',createdAt:新日期(),更新日期:新日期()},
    { firstName:'selcuk',lastName:'gecer',电子邮件:'selcuk@gmail.com',createdAt:新日期(),updatedAt:新日期()},
    {名字:'turhan',姓氏:'bozkurt',电子邮件:'turhan@gmail.com',createdAt:新日期(),updatedAt:新日期()}
    ],{}
    );
    },
    下来:异步(queryInterface,Sequelize)=> {
    等待 queryInterface.bulkDelete('User2s', null, {});
    }
    };
  • 为 User2 执行上述种子
    npx sequelize-cli db:seed:all
    注意以上失败
    错误:关系“User2s”的“id”列中的空值违反非空约束
    因为生成的 CREATE TABLE sql 并没有真正使用 defaultValue 变量
  • 最佳答案

    我不得不说我对使用 UUID 作为 PK id 这个基本主题缺乏适当的文档、示例和 stackoverflow 答案感到非常惊讶。我正在下面详细记录答案,这样其他人就不会像我一样受苦。
    经过多次尝试和错误,我找到了解决方案;
    事实证明,使用 postgreSQL,

  • 使用 postgreSQL,默认情况下仅启用“plpgsql”扩展。
    因此,要使用“uuid_generate_v1()”需要通过发布启用“uuid-ossp”postgreSQL 扩展;
    "如果不存在则创建扩展"uuid-ossp";
  • 并且在迁移文件中需要使用;
    默认值:Sequelize.literal('uuid_generate_v4()'),

  • 这是迁移文件中的代码片段;
    'use strict';
    module.exports = {
      up: async (queryInterface, Sequelize) => {
    // create the table 'users' for 'User' model
    await queryInterface.createTable(
      // 'tableName' input to queryInterface.createTable
      'Users', 
      // 'attributes' input to queryInterface.createTable
      {
    //      CREATE TABLE exp15c."Users"
    //      (
    //          id integer NOT NULL DEFAULT nextval('exp15c."Users_id_seq"'::regclass),
    //          "firstName" character varying(255) COLLATE pg_catalog."default",
    //          "lastName" character varying(255) COLLATE pg_catalog."default",
    //          email character varying(255) COLLATE pg_catalog."default",
    //          "createdAt" timestamp with time zone NOT NULL,
    //          "updatedAt" timestamp with time zone NOT NULL,
    //          CONSTRAINT "Users_pkey" PRIMARY KEY (id)
    //      )
        // NOTE below block creates above table
    //      id: {
    //        allowNull: false,
    //        autoIncrement: true,
    //        primaryKey: true,
    //        type: Sequelize.INTEGER
    //      },
        // NOTE above using INTEGER for id, below is using UUID
        id: {
          allowNull: false,
    //    autoIncrement: true,  // WRONG, with this "npx sequelize-cli db:migrate" fails with 'ERROR syntax error at or near "SERIAL"'
          // NOTE with postgreSQL, by default only "plpgsql" extension is enabled. To use "uuid_generate_v1()" need to enable "uuid-ossp" postgreSQL extension via issuing;  "CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
          //  "https://www.postgresqltutorial.com/postgresql-uuid/"
          defaultValue: Sequelize.literal('uuid_generate_v4()'), // NOTE results in "id UUID NOT NULL DEFAULT uuid_generate_v4()" in generated CREATE TABLE which needs need to enable "uuid-ossp" postgreSQL extension via issuing;  "CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
    //    defaultValue: uuid_v4(),                  // WRONG ends up adding "DEFAULT 'a1d10f9f-aa6f-493d-8442-5a6ebc304079'::uuid" in "id uuid NOT NULL DEFAULT 'a1d10f9f-aa6f-493d-8442-5a6ebc304079'::uuid", which  fails upon "npx sequelize-cli db:seed:all" with "ERROR: Validation error" 
    //    defaultValue: Sequelize.UUIDV4,           // WRONG results in "id UUID NOT NULL"
    //    defaultValue: Sequelize.DataTypes.UUIDV4, // WRONG equivalent to above line, results in "id uuid NOT NULL"
    //    defaultValue: require('sequelize').UUIDV4,// WRONG equivalent to above line, results in "id uuid NOT NULL"
          primaryKey: true,
          type: Sequelize.UUID         
        },
        // NOTE above block creates below table
    //  CREATE TABLE exp15c."Users"
    //  (
    //      id uuid NOT NULL DEFAULT uuid_generate_v4(),
    //   -- id uuid NOT NULL DEFAULT 'a1d10f9f-aa6f-493d-8442-5a6ebc304079'::uuid,
    //   -- id uuid NOT NULL,
    //      "firstName" character varying(255) COLLATE pg_catalog."default",
    //      "lastName" character varying(255) COLLATE pg_catalog."default",
    //      email character varying(255) COLLATE pg_catalog."default",
    //      "createdAt" timestamp with time zone NOT NULL,
    //      "updatedAt" timestamp with time zone NOT NULL,
    //      CONSTRAINT "Users_pkey" PRIMARY KEY (id)
    //  )      
            firstName: {
              type: Sequelize.STRING
            },
            lastName: {
              type: Sequelize.STRING
            },
            email: {
              type: Sequelize.STRING
            },
            createdAt: {
              allowNull: false,
              type: Sequelize.DATE
            },
            updatedAt: {
              allowNull: false,
              type: Sequelize.DATE
            }
          },
          // 'options' input to queryInterface.createTable
          {schema: process.env.DB_POSTGRESQL_SCHEMA_NAME}
        );
      },
      down: async (queryInterface, Sequelize) => {
        await queryInterface.dropTable('Users');
      }
    };
    

    关于sequelize.js - sequelize(和 sequelize-cli)queryInterface.createTable 在 PostgreSQL 上,PK id 类型为 UUID,defaultValue : Sequelize. DataTypes.UUIDV4 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67389165/

    相关文章:

    javascript - Sequelize : Bulk update or insert into MSSQL DB

    Node.js Sequelize 无法读取 nulll 的属性

    node.js - 在单个对象而不是嵌套对象中显示所有数据

    sequelize.js - 按第一个模型在 sequelize 中订购

    typescript - 使用 Typescript 进行 Sequelize 无法正确解析类型

    dry - 在使用 JSData 和 Sequelize 时保持 DRY

    javascript - Sequelize : instance. get 不是一个函数

    node.js - 用 Sequelize 返回外键的表数据

    javascript - Sequelize迁移错误: Cannot read property 'length' of undefined

    mysql - 当一条路由当前正在向数据库插入大量数据时,如何使所有其他路由正常工作?