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
上面命令中安装的库的简单说明:
sequelize是 sequelize 库本身。
sequelize-cli是一个使我们能够通过sequelize
CLI 与数据库交互的包。
pg是 postgres 的缩写,是 Node.js 的 Postgres 客户端
pg-hstore是一个用于将 JSON 数据序列化和反序列化为 hstore 格式的节点包。
接下来,让我们创建 sequelize 配置,为此,请运行下面的命令来创建一个名为.sequelizerc
touch .sequelizerc
将以下代码复制到.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'),
}
Sequelize 使用该.sequelizerc
文件按照指定路径生成配置和模型。
接下来,我们通过运行以下命令来生成配置:
sequelize init
现在,您应该有一个名为“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',
},
}
由于我们的重点是将 Sequelize 与 Postgres 结合使用,因此我们已将配置简化为特定于 Postgres 的。
由于我们使用的是 Postgres,因此我们将使用连接字符串连接到数据库。创建两个 Postgres 数据库,一个用于开发,一个用于测试(如果您的项目需要测试)。
如何创建 Postgres 数据库连接字符串
如果您已经创建数据库,则可以跳到下一部分。
方法 1
如果您已在本地安装了 Postgres,请按照以下步骤创建数据库并生成连接字符串。打开终端并运行以下命令:
createdb dev_db -U <db_user>
createdb test_db -U <db_user>
上述数据库的连接字符串将是:
postgres://<db_user>:<db_password>@127.0.0.1:5432/dev_db
postgres://<db_user>:<db_password>@127.0.0.1:5432/test_db
现在,创建一个.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
请注意,如果您使用 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
上述每个命令将分别在目录中生成迁移和/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,
},
按如下方式编辑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
定义模型关系
我们有三种相互关联的模型,如下所示
- 一个用户有多篇帖子,每篇帖子属于一个用户(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
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
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
现在是时候运行迁移了,它会将迁移内容转换为数据库中的表。运行
sequelize db:migrate
如果一切顺利,表格就会生成,我们就可以开始将数据推送到数据库中。
将数据播种到数据库
让我们用一些虚拟数据填充数据库。运行以下命令生成模型的种子文件。
sequelize seed:generate --name User
sequelize seed:generate --name Post
sequelize seed:generate --name Comment
上述命令将分别为、和模型生成三个文件xxxx-User.js
、、和。xxxx-Post.js
xxxx-Comment.js
User
Post
Comment
按如下方式编辑种子文件:
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
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
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
现在,运行以下命令来播种数据库:
sequelize db:seed:all
您可以在此处克隆本文的完整代码
哟!暂时就这些。在本文的第二部分,我将在此基础上实现博客的 CRUD 功能。敬请期待!📌
推荐资源
本文最初发表在我的博客上
链接:https://dev.to/nedsoft/getting-started-with-sequelize-and-postgres-emp