Sequelize 和 Postgres 入门

2025-06-10

Sequelize 和 Postgres 入门

Sequelize是一个基于 Promise 的 Node.js ORM,适用于 Postgres、MySQL、MariaDB、SQLite 和 Microsoft SQL Server。它具有可靠的事务支持、关系、即时加载和延迟加载、读取复制等功能。

ORM 库是一个完全普通的库,用你选择的语言编写,它封装了操作数据所需的代码,因此你不再使用 SQL;你可以直接使用你正在使用的语言与对象进行交互 - stackoverflow

虽然 Sequelize 支持其他一些数据库客户端,但本文重点介绍如何将 Sequelize 与 Postgres 结合使用。我们将构建一个简单的博客,用户可以在其中创建帖子、查看帖子以及添加评论。

本文分为两部分:

  • 第一部分 - Sequelize 设置、配置、迁移和播种。
  • 第二部分 - 使用 Sequelize 执行 CRUD。

要求

  • NodeJs已安装
  • 已安装 npm 或 yarn

第一部分

如果您尚未创建 Express 项目,请快速创建并在终端中打开该项目。在项目的根文件夹中,运行以下命令来安装必要的依赖项:



npm install sequelize sequelize-cli pg pg-hstore


Enter fullscreen mode Exit fullscreen mode

上面命令中安装的库的简单说明:

sequelize是 sequelize 库本身。

sequelize-cli是一个使我们能够通过sequelizeCLI 与数据库交互的包。

pg是 postgres 的缩写,是 Node.js 的 Postgres 客户端

pg-hstore是一个用于将 JSON 数据序列化和反序列化为 hstore 格式的节点包。

接下来,让我们创建 sequelize 配置,为此,请运行下面的命令来创建一个名为.sequelizerc



touch .sequelizerc


Enter fullscreen mode Exit fullscreen mode

将以下代码复制到.seqluelizerc文件中:



const path = require('path')

module.exports = {
  config: path.resolve('./database/config', 'config.js'),
  'models-path': path.resolve('./database/models'),
  'seeders-path': path.resolve('./database/seeders'),
  'migrations-path': path.resolve('./database/migrations'),
}


Enter fullscreen mode Exit fullscreen mode

Sequelize 使用该.sequelizerc文件按照指定路径生成配置和模型。

接下来,我们通过运行以下命令来生成配置:



sequelize init


Enter fullscreen mode Exit fullscreen mode

现在,您应该有一个名为“scaffolding”的新目录database,如下所示:

接下来,让我们编辑database/config/config.js用下面的代码
替换的内容:database/config/config.js



require('dotenv').config()

module.exports = {
  development: {
    url: process.env.DEV_DATABASE_URL,
    dialect: 'postgres',
  },
  test: {
    url: process.env.TEST_DATABASE_URL,
    dialect: 'postgres',
  },
  production: {
    url: process.env.DATABASE_URL,
    dialect: 'postgres',
  },
}


Enter fullscreen mode Exit fullscreen mode

由于我们的重点是将 Sequelize 与 Postgres 结合使用,因此我们已将配置简化为特定于 Postgres 的。

由于我们使用的是 Postgres,因此我们将使用连接字符串连接到数据库。创建两个 Postgres 数据库,一个用于开发,一个用于测试(如果您的项目需要测试)。

如何创建 Postgres 数据库连接字符串

如果您已经创建数据库,则可以跳到下一部分。

方法 1

如果您已在本地安装了 Postgres,请按照以下步骤创建数据库并生成连接字符串。打开终端并运行以下命令:



createdb dev_db -U <db_user>
createdb test_db -U <db_user>



Enter fullscreen mode Exit fullscreen mode

上述数据库的连接字符串将是:



postgres://<db_user>:<db_password>@127.0.0.1:5432/dev_db
postgres://<db_user>:<db_password>@127.0.0.1:5432/test_db


Enter fullscreen mode Exit fullscreen mode

现在,创建一个.env文件并将下面的代码片段复制到其中。



DATABASE_URL=
DEV_DATABASE_URL=postgres://<db_user>:<db_password>@127.0.0.1:5432/dev_db
TEST_DATABASE_URL=postgres://<db_user>:<db_password>@127.0.0.1:5432/test_db


Enter fullscreen mode Exit fullscreen mode

请注意,如果您使用 Heroku 进行生产,DATABASE_URL一旦您添加 Postgres 插件,Heroku 将生成一个连接字符串并注入到环境变量中。

方法 2

如果您没有在本地安装 Postgres,您可以使用ElephantSQL来创建数据库。

创建模型和迁移

我们需要创建 User、Post 和 Comment 模型。请运行以下命令:



sequelize model:generate --name User --attributes name:string,email:string

sequelize model:generate --name Post --attributes title:string,content:text,userId:integer

sequelize model:generate --name Comment --attributes postId:integer,comment:text,userId:integer


Enter fullscreen mode Exit fullscreen mode

上述每个命令将分别在目录中生成迁移和/database/migrations模型database/models

注意--attributes,确保定义之间没有空格。

例如,由于属性之间的空格--attributes postId:integer, comment:text, userId:integer将引发错误。ERROR: Attribute '' cannot be parsed: Cannot read property 'dataType' of undefined

接下来,我们需要对迁移和模型进行一些更改。
首先,我们需要NOT NULL为属性(userId、postId)添加约束。我第一次使用 Sequelize 时并不知道这一点,而且模型预加载功能也无法正常工作。在迁移中,请按如下所示FOREIGN_KEY编辑属性:FOREIGN_KEY



userId: {
      type: Sequelize.INTEGER,
      allowNull: false,
    },

postId: {
      type: Sequelize.INTEGER,
      allowNull: false,
    },


Enter fullscreen mode Exit fullscreen mode

按如下方式编辑models/index.js文件:




const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const envConfigs =  require('../config/config');

const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = envConfigs[env];
const db = {};

let sequelize;
if (config.url) {
  sequelize = new Sequelize(config.url, config);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter(file => {
    return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
  })
  .forEach(file => {
    const model = sequelize['import'](path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;

//models/index.js



Enter fullscreen mode Exit fullscreen mode

定义模型关系

我们有三种相互关联的模型,如下所示

  • 一个用户有多篇帖子,每篇帖子属于一个用户(1:n)
  • 一个用户有多条评论,每条评论属于一个用户(1:n)
  • 一篇帖子有多条评论,一条评论属于一篇帖子(1:n)

为了以编程方式建立上述关系,让我们按如下方式编辑模型:



module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define('User', {
    name: DataTypes.STRING,
    email: DataTypes.STRING
  }, {});
  User.associate = function(models) {
    // associations can be defined here
    User.hasMany(models.Post, {
      foreignKey: 'userId',
      as: 'posts',
      onDelete: 'CASCADE',
    });

    User.hasMany(models.Comment, {
      foreignKey: 'userId',
      as: 'comments',
      onDelete: 'CASCADE',
    });
  };
  return User;
};

// database/models/user.js


Enter fullscreen mode Exit fullscreen mode


module.exports = (sequelize, DataTypes) => {
  const Post = sequelize.define('Post', {
    title: DataTypes.STRING,
    content: DataTypes.TEXT,
    userId: DataTypes.INTEGER
  }, {});
  Post.associate = function(models) {
    // associations can be defined here
    Post.hasMany(models.Comment, {
      foreignKey: 'postId',
      as: 'comments',
      onDelete: 'CASCADE',
    });

    Post.belongsTo(models.User, {
      foreignKey: 'userId',
      as: 'author',
      onDelete: 'CASCADE',
    })
  };
  return Post;
};

// database/models/post.js


Enter fullscreen mode Exit fullscreen mode


module.exports = (sequelize, DataTypes) => {
  const Comment = sequelize.define('Comment', {
    postId: DataTypes.INTEGER,
    comment: DataTypes.TEXT,
    userId: DataTypes.INTEGER
  }, {});
  Comment.associate = function(models) {
    // associations can be defined here
    Comment.belongsTo(models.User, {
      foreignKey: 'userId',
      as: 'author'
    });
    Comment.belongsTo(models.Post, {
      foreignKey: 'postId',
      as: 'post'
    });
  };
  return Comment;
};

// database/models/comment.js


Enter fullscreen mode Exit fullscreen mode

现在是时候运行迁移了,它会将迁移内容转换为数据库中的表。运行



sequelize db:migrate



Enter fullscreen mode Exit fullscreen mode

如果一切顺利,表格就会生成,我们就可以开始将数据推送到数据库中。

将数据播种到数据库

让我们用一些虚拟数据填充数据库。运行以下命令生成模型的种子文件。



sequelize seed:generate --name User

sequelize seed:generate --name Post

sequelize seed:generate --name Comment


Enter fullscreen mode Exit fullscreen mode

上述命令将分别和模型生成三个文件xxxx-User.js、、xxxx-Post.jsxxxx-Comment.jsUserPostComment

按如下方式编辑种子文件:



module.exports = {
  up: (queryInterface, Sequelize) => queryInterface.bulkInsert(
    'Users',
    [
      {
        name: 'Jane Doe',
        email: 'janedoe@example.com',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
      {
        name: 'Jon Doe',
        email: 'jondoe@example.com',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ],
    {},
  ),

  down: (queryInterface, Sequelize) => queryInterface.bulkDelete('Users', null, {}),
};

// database/seeds/xxxx-User.js


Enter fullscreen mode Exit fullscreen mode


module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.bulkInsert(
      "Posts",
      [
        {
          userId: 1,
          title: "hispotan de nu",
          content:
            "Nulla mollis molestie lorem. Quisque ut erat. Curabitur gravida nisi at nibh.",
          createdAt: new Date(),
          updatedAt: new Date()
        },
        { 
          userId: 2,
          title: 'some dummy title',
          content:
            "Maecenas tincidunt lacus at velit. Vivamus vel nulla eget eros elementum pellentesque. Quisque porta volutpat erat.",
          createdAt: new Date(),
          updatedAt: new Date()
        }
      ],

      {}
    ),

  down: (queryInterface, Sequelize) =>
    queryInterface.bulkDelete("Posts", null, {})
};
// database/seeds/xxxx-Post.js



Enter fullscreen mode Exit fullscreen mode


module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.bulkInsert(
      "Comments",
      [
        {
          userId: 1,
          postId: 2,
          comment:
            "Nulla mollis molestie lorem. Quisque ut erat. Curabitur gravida nisi at nibh.",
          createdAt: new Date(),
          updatedAt: new Date()
        },
        {
          userId: 2,
          postId: 1,
          comment:
            "Maecenas tincidunt lacus at velit. Vivamus vel nulla eget eros elementum pellentesque. Quisque porta volutpat erat.",
          createdAt: new Date(),
          updatedAt: new Date()
        }
      ],
      {}
    ),

  down: (queryInterface, Sequelize) =>
    queryInterface.bulkDelete("Comments", null, {})
};

// database/seeds/xxxx-Comment.js


Enter fullscreen mode Exit fullscreen mode

现在,运行以下命令来播种数据库:



sequelize db:seed:all


Enter fullscreen mode Exit fullscreen mode

您可以在此处克隆本文的完整代码

哟!暂时就这些。在本文的第二部分,我将在此基础上实现博客的 CRUD 功能。敬请期待!📌

推荐资源

本文最初发表在我的博客上

链接:https://dev.to/nedsoft/getting-started-with-sequelize-and-postgres-emp
PREV
验证 HTML 表单输入的技巧
NEXT
⭐ 一款开源工具,可在浏览器中轻松构建 React 企业应用程序