可以在此处访问此博客的代码
可以在此处访问此博客的代码
可以在此处访问此博客的 Markdown
Sequelize 是最著名的 Node ORM,功能相当丰富,但在使用它的时候,我花了很多时间在文档和各种谷歌搜索之间徘徊。
这份 Cheatsheet 正是我一直想要的,但却一直找不到。
发现任何错误或缺失的内容?请在下方评论,或者更好的是,向文末链接的仓库发送拉取请求。
npm install --save sequelize
您还需要安装您正在使用的数据库的驱动程序。
# One of the following:
npm install --save pg pg-hstore # Postgres If node version < 14 use pg@7.12.1 instead
npm install --save mysql2
npm install --save mariadb
npm install --save sqlite3
npm install --save tedious # Microsoft SQL Server
必须创建一个 Sequelize 实例才能连接到数据库。默认情况下,此连接保持打开并用于所有查询,但可以显式关闭。
const Sequelize = require('sequelize');
// Option 1: Passing parameters separately
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: /* one of 'mysql' | 'mariadb' | 'postgres' | 'mssql' */
});
// Option 2: Passing a connection URI
const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname');
// For SQLite, use this instead
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'path/to/database.sqlite'
});
有关连接不同方言的更多详细信息,请查看官方文档
.authenticate()
可以与创建的实例一起使用来检查连接是否正常工作。
sequelize
.authenticate()
.then(() => {
console.log("Connection has been established successfully.");
})
.catch((err) => {
console.error("Unable to connect to the database:", err);
});
sequelize.close();
要定义模型和表之间的映射,我们可以使用该.define()
方法
设置仅具有属性及其数据类型的基本模型
const ModelName = sequelize.define("tablename", {
// s will be appended automatically to the tablename
firstColumn: Sequelize.INTEGER,
secondColumn: Sequelize.STRING,
});
要获取 Sequelize 支持的所有数据类型的列表,请查看官方文档
除了数据类型之外,还可以在每列上设置许多其他选项
const ModelName = sequelize.define("tablename", {
firstColumn: {
// REQUIRED
type: Sequelize.INTEGER,
// OPTIONAL
allowNull: false, // true by default
defaultValue: 1,
primaryKey: true, // false by default
autoIncrement: true, // false by default
unique: true,
field: "first_column", // To change the field name in actual table
},
});
要创建复合唯一键,请为要包含在复合唯一键中的所有列中的约束赋予相同的名称
const ModelName = sequelize.define("tablename", {
firstColumn: {
type: Sequelize.INTEGER,
unique: "compositeIndex",
},
secondColumn: {
type: Sequelize.INTEGER,
unique: "compositeIndex",
},
});
也可以使用索引创建它们
const ModelName = sequelize.define(
"tablename",
{
firstColumn: Sequelize.INTEGER,
secondColumn: Sequelize.INTEGER,
},
{
indexes: [
{
unique: true,
fields: ["firstColumn", "secondColumn"],
},
],
}
);
Getter 可用于在经过某些处理后获取列的值。Setter
可用于在将值保存到表中之前对其进行处理。
const Employee = sequelize.define("employee", {
name: {
type: Sequelize.STRING,
allowNull: false,
get() {
const title = this.getDataValue("title");
// 'this' allows you to access attributes of the instance
return this.getDataValue("name") + " (" + title + ")";
},
},
title: {
type: Sequelize.STRING,
allowNull: false,
set(val) {
this.setDataValue("title", val.toUpperCase());
},
},
});
Employee.create({ name: "John Doe", title: "senior engineer" }).then(
(employee) => {
console.log(employee.get("name")); // John Doe (SENIOR ENGINEER)
console.log(employee.get("title")); // SENIOR ENGINEER
}
);
有关 Getters 和 Setters 的更多详细信息,请查看官方文档
验证自动运行于create
,update
并且save
const ModelName = sequelize.define("tablename", {
firstColumn: {
type: Sequelize.STRING,
validate: {
is: ["^[a-z]+$", "i"], // will only allow letters
is: /^[a-z]+$/i, // same as the previous example using real RegExp
not: ["[a-z]", "i"], // will not allow letters
isEmail: true, // checks for email format (foo@bar.com)
isUrl: true, // checks for url format (http://foo.com)
isIP: true, // checks for IPv4 (129.89.23.1) or IPv6 format
isIPv4: true, // checks for IPv4 (129.89.23.1)
isIPv6: true, // checks for IPv6 format
isAlpha: true, // will only allow letters
isAlphanumeric: true, // will only allow alphanumeric characters, so "_abc" will fail
isNumeric: true, // will only allow numbers
isInt: true, // checks for valid integers
isFloat: true, // checks for valid floating point numbers
isDecimal: true, // checks for any numbers
isLowercase: true, // checks for lowercase
isUppercase: true, // checks for uppercase
notNull: true, // won't allow null
isNull: true, // only allows null
notEmpty: true, // don't allow empty strings
equals: "specific value", // only allow a specific value
contains: "foo", // force specific substrings
notIn: [["foo", "bar"]], // check the value is not one of these
isIn: [["foo", "bar"]], // check the value is one of these
notContains: "bar", // don't allow specific substrings
len: [2, 10], // only allow values with length between 2 and 10
isUUID: 4, // only allow uuids
isDate: true, // only allow date strings
isAfter: "2011-11-05", // only allow date strings after a specific date
isBefore: "2011-11-05", // only allow date strings before a specific date
max: 23, // only allow values <= 23
min: 23, // only allow values >= 23
isCreditCard: true, // check for valid credit card numbers
// Examples of custom validators:
isEven(value) {
if (parseInt(value) % 2 !== 0) {
throw new Error("Only even values are allowed!");
}
},
},
},
});
const ModelName = sequelize.define(
"tablename",
{
firstColumn: Sequelize.INTEGER,
secondColumn: Sequelize.INTEGER,
},
{
validate: {
// Define your Model Wide Validations here
checkSum() {
if (this.firstColumn + this.secondColumn < 10) {
throw new Error("Require sum of columns >=10");
}
},
},
}
);
const ModelName = sequelize.define(
"tablename",
{
firstColumn: Sequelize.INTEGER,
},
{
timestamps: true, // Enable timestamps
createdAt: false, // Don't create createdAt
updatedAt: false, // Don't create updatedAt
updatedAt: "updateTimestamp", // updatedAt should be called updateTimestamp
}
);
Sequelize 可以自动创建模型中定义的表、关系和约束
ModelName.sync(); // Create the table if not already present
// Force the creation
ModelName.sync({ force: true }); // this will drop the table first and re-create it afterwards
ModelName.drop(); // drop the tables
您可以使用 sequelize 一次管理所有模型
sequelize.sync(); // Sync all models that aren't already in the database
sequelize.sync({ force: true }); // Force sync all models
sequelize.sync({ force: true, match: /_test$/ }); // Run .sync() only if database name ends with '_test'
sequelize.drop(); // Drop all tables
Sequelize 模型是 ES6 类。我们可以轻松添加自定义实例或类级别的方法。
const ModelName = sequelize.define("tablename", {
firstColumn: Sequelize.STRING,
secondColumn: Sequelize.STRING,
});
// Adding a class level method
ModelName.classLevelMethod = function () {
return "This is a Class level method";
};
// Adding a instance level method
ModelName.prototype.instanceLevelMethod = function () {
return [this.firstColumn, this.secondColumn].join(" ");
};
const User = sequelize.define(
"User",
{
/* attributes */
},
{
indexes: [
// Create a unique index on email
{
unique: true,
fields: ["email"],
},
// Creates a gin index on data with the jsonb_path_ops operator
{
fields: ["data"],
using: "gin",
operator: "jsonb_path_ops",
},
// By default index name will be [table]_[fields]
// Creates a multi column partial index
{
name: "public_by_author",
fields: ["author", "status"],
where: {
status: "public",
},
},
// A BTREE index with an ordered field
{
name: "title_index",
using: "BTREE",
fields: [
"author",
{
attribute: "title",
collate: "en_US",
order: "DESC",
length: 5,
},
],
},
],
}
);
定义有四种类型。它们成对使用。
例如,我们定义两个模型
const Foo = sequelize.define("foo" /* ... */);
const Bar = sequelize.define("bar" /* ... */);
我们将要调用其函数的模型称为源模型,作为参数传递的模型称为目标模型。
Foo.hasOne(Bar, {
/* options */
});
这说明 Foo 和 Bar 之间存在一对一关系,外键定义在 Bar 中
Foo.belongsTo(Bar, {
/* options */
});
这说明 Foo 和 Bar 之间存在一对一或一对多关系,且外键定义在 Foo 中
Foo.hasMany(Bar, {
/* options */
});
这说明 Foo 和 Bar 之间存在一对多关系,外键定义在 Bar 中
Foo.belongsToMany(Bar, {
// REQUIRED
through: "C", // Model can also be passed here
/* options */
});
这表明 Foo 和 Bar 之间存在多对多关系,通过连接表 C
要建立一对一关系,我们只需编写
Foo.hasOne(Bar);
Bar.belongsTo(Foo);
在上述情况下,未传递任何选项。这将自动在 Bar 中创建一个外键列,引用 Foo 的主键。如果 Foo 的主键列名为 email,则在 Bar 中生成的列将为 fooEmail。
可以传递以下选项来定制关系。
Foo.hasOne(Bar, {
foreignKey: "customNameForFKColumn", // Name for new column added to Bar
sourceKey: "email", // Column in Foo that FK will reference to
// The possible choices are RESTRICT, CASCADE, NO ACTION, SET DEFAULT and SET NULL
onDelete: "RESTRICT", // Default is SET NULL
onUpdate: "RESTRICT", // Default is CASCADE
});
Bar.belongsTo(Foo, {
foreignKey: "customNameForFKColumn", // Name for new column added to Bar
});
要建立一对一关系,我们只需编写
Foo.hasMany(Bar);
Bar.belongsTo(Foo);
在上述情况下,未传递任何选项。这将自动在 Bar 中创建一个外键列,引用 Foo 的主键。如果 Foo 的主键列名为 email,则在 Bar 中生成的列将为 fooEmail。
可以传递以下选项来定制关系。
Foo.hasMany(Bar, {
foreignKey: "customNameForFKColumn", // Name for new column added to Bar
sourceKey: "email", // Column in Foo that FK will reference to
// The possible choices are RESTRICT, CASCADE, NO ACTION, SET DEFAULT and SET NULL
onDelete: "RESTRICT", // Default is SET NULL
onUpdate: "RESTRICT", // Default is CASCADE
});
Bar.belongsTo(Foo, {
foreignKey: "customNameForFKColumn", // Name for new column added to Bar
});
要建立多对多关系,我们只需编写
// This will create a new table rel referencing the PK(by default) of both the tables
Foo.belongsToMany(Bar, { through: "rel" });
Bar.belongsToMany(Foo, { through: "rel" });
可以传递以下选项来定制关系。
Foo.belongsToMany(Bar, {
as: "Bar",
through: "rel",
foreignKey: "customNameForFoo", // Custom name for column in rel referencing to Foo
sourceKey: "name", // Column in Foo which rel will reference to
});
Bar.belongsToMany(Foo, {
as: "Foo",
through: "rel",
foreignKey: "customNameForBar", // Custom name for column in rel referencing to Bar
sourceKey: "name", // Column in Foo which rel will reference to
});
创建实例有两种方式
我们可以使用 build 方法创建非持久化(不保存到表中)实例。它们将自动获取定义模型时指定的默认值。
要保存到表中,我们需要显式地保存这些实例。
const instance = ModelName.build({
firstColumn: "Lorem Ipsum",
secondColumn: "Dotor",
});
// To save this instance to the db
instance.save().then((savedInstance) => {});
我们可以创建一个方法来创建持久(保存到表中)实例
const instance = ModelName.create({
firstColumn: "Lorem Ipsum",
secondColumn: "Dotor",
});
有两种方法可以更新任何实例
// Way 1
instance.secondColumn = "Updated Dotor";
instance.save().then(() => {});
// To update only some of the modified fields
instance.save({ fields: ["secondColumn"] }).then(() => {});
// Way 2
instance
.update({
secondColumn: "Updated Dotor",
})
.then(() => {});
// To update only some of the modified fields
instance
.update(
{
secondColumn: "Updated Dotor",
},
{ fields: ["secondColumn"] }
)
.then(() => {});
删除/销毁任何实例
instance.destroy().then(() => {});
返回具有给定主键值的行。
ModelName.findByPK(PKvalue).then((foundResult) => {});
返回符合给定条件的第一行。
ModelName.findOne({
// Optional options
// Filtering results using where
where: { firstColumn: "value" },
// Returning only specified columns
attributes: ["firstColumn", "secondColumn"],
}).then((foundResult) => {});
返回符合指定条件的行。如果不存在这样的行,则创建并返回该行。
ModelName.findOrCreate({
// Conditions that must be met
where: { firstColumn: "lorem ipsum" },
// Value of other columns to be set if no such row found
defaults: { secondColumn: "dotor" },
}).then(([result, created]) => {}); //Created is a bool which tells created or not
返回满足条件的所有行
ModelName.findAll({
// Optional Options
where: {
firstColumn: "lorem ipsum",
},
offset: 10,
limit: 2,
}).then((results) => {});
返回满足条件的所有行及其计数
ModelName.findAndCountAll({
where: {
firstColumn: "lorem ipsum",
},
}).then((results) => {
console.log(results.count);
console.log(results.rows);
});
返回满足条件的行数
ModelName.count({
where: {
firstColumn: "lorem ipsum",
},
}).then((c) => {});
返回具有给定条件的最大值的列的值
ModelName.max("age", {
where: {
firstColumn: "lorem ipsum",
},
}).then((maxAge) => {});
返回具有给定条件的最小值的列的值
ModelName.min("age", {
where: {
firstColumn: "lorem ipsum",
},
}).then((minAge) => {});
返回满足给定条件的列的所有值的总和
ModelName.sum({
where: {
firstColumn: "lorem ipsum",
},
}).then((sumAge) => {});
哪里可以用来过滤我们处理的结果
我们可以直接传递值
ModelName.findAll({
where: {
firstColumn: "lorem ipsum",
},
});
我们可以使用 AND 和 OR
const Op = Sequelize.Op;
ModelName.findAll({
where: {
[Op.and]: [{ secondColumn: 5 }, { thirdColumn: 6 }],
[Op.or]: [{ secondColumn: 5 }, { secondColumn: 6 }],
},
});
我们可以使用其他各种运算符
const Op = Sequelize.Op;
ModelName.findAll({
where: {
firstColumn: {
[Op.ne]: "lorem ipsum dotor", // Not equal to
},
},
});
我们也可以混合搭配
const Op = Sequelize.Op;
ModelName.findAll({
where: {
[Op.or]: {
[Op.lt]: 1000,
[Op.eq]: null,
},
},
});
以下是运营商的完整列表
const Op = Sequelize.Op
[Op.and]: [{a: 5}, {b: 6}] // (a = 5) AND (b = 6)
[Op.or]: [{a: 5}, {a: 6}] // (a = 5 OR a = 6)
[Op.gt]: 6, // > 6
[Op.gte]: 6, // >= 6
[Op.lt]: 10, // < 10
[Op.lte]: 10, // <= 10
[Op.ne]: 20, // != 20
[Op.eq]: 3, // = 3
[Op.is]: null // IS NULL
[Op.not]: true, // IS NOT TRUE
[Op.between]: [6, 10], // BETWEEN 6 AND 10
[Op.notBetween]: [11, 15], // NOT BETWEEN 11 AND 15
[Op.in]: [1, 2], // IN [1, 2]
[Op.notIn]: [1, 2], // NOT IN [1, 2]
[Op.like]: '%hat', // LIKE '%hat'
[Op.notLike]: '%hat' // NOT LIKE '%hat'
[Op.iLike]: '%hat' // ILIKE '%hat' (case insensitive) (PG only)
[Op.notILike]: '%hat' // NOT ILIKE '%hat' (PG only)
[Op.startsWith]: 'hat' // LIKE 'hat%'
[Op.endsWith]: 'hat' // LIKE '%hat'
[Op.substring]: 'hat' // LIKE '%hat%'
[Op.regexp]: '^[h|a|t]' // REGEXP/~ '^[h|a|t]' (MySQL/PG only)
[Op.notRegexp]: '^[h|a|t]' // NOT REGEXP/!~ '^[h|a|t]' (MySQL/PG only)
[Op.iRegexp]: '^[h|a|t]' // ~* '^[h|a|t]' (PG only)
[Op.notIRegexp]: '^[h|a|t]' // !~* '^[h|a|t]' (PG only)
[Op.like]: { [Op.any]: ['cat', 'hat']}
// LIKE ANY ARRAY['cat', 'hat'] - also works for iLike and notLike
[Op.overlap]: [1, 2] // && [1, 2] (PG array overlap operator)
[Op.contains]: [1, 2] // @> [1, 2] (PG array contains operator)
[Op.contained]: [1, 2] // <@ [1, 2] (PG array contained by operator)
[Op.any]: [2,3] // ANY ARRAY[2, 3]::INTEGER (PG only)
[Op.col]: 'user.organization_id' // = "user"."organization_id", with dialect specific column identifiers, PG in this example
[Op.gt]: { [Op.all]: literal('SELECT 1') }
// > ALL (SELECT 1)
[Op.contains]: 2 // @> '2'::integer (PG range contains element operator)
[Op.contains]: [1, 2] // @> [1, 2) (PG range contains range operator)
[Op.contained]: [1, 2] // <@ [1, 2) (PG range is contained by operator)
[Op.overlap]: [1, 2] // && [1, 2) (PG range overlap (have points in common) operator)
[Op.adjacent]: [1, 2] // -|- [1, 2) (PG range is adjacent to operator)
[Op.strictLeft]: [1, 2] // << [1, 2) (PG range strictly left of operator)
[Op.strictRight]: [1, 2] // >> [1, 2) (PG range strictly right of operator)
[Op.noExtendRight]: [1, 2] // &< [1, 2) (PG range does not extend to the right of operator)
[Op.noExtendLeft]: [1, 2] // &> [1, 2) (PG range does not extend to the left of operator)
ModelName.findAll({
order: [
["firstColumn", "DESC"],
["secondColumn", "ASC"],
],
});
有关订购的更多详细信息,请查看官方文档
ModelName.findAll({
offset: 5, // Skip the first five results
limit: 5, // Return only five results
});
发送拉取请求以添加/修改此帖子。