如何使用基本和高级Sequelize功能

901 阅读18分钟

使用基本和高级Sequelize功能

Sequelize是一个JavaScript库,可以管理大多数流行的数据库,如PostgreSQL、MySQL、SQLite和MSSQL。对象关系映射器(ORM)是用来将对象关系语法转换为数据库模式的。通常情况下,sequelize是与Node.js一起使用的。我们可以把Sequelize称为ORM。

Sequelize只支持关系型数据库。像Mongo DB或其他NoSQL数据库不被支持。Sequelize支持坚实的交易、急切和懒惰的加载、关系、读取复制和其他很酷的功能。

在本教程结束时,读者将充分了解以下内容。

  • 如何安装Sequelize。
  • 如何安装与不同数据库相关的驱动程序。
  • 连接到数据库并测试连接。
  • 如何使用Sequelize CLI。
  • 模型查询(插入、更新、删除)。
  • 关联(一到一,一到多,多到多)。
  • Node.js运行时

前提条件

在我们继续前进之前,建议具备以下条件。

  • 有JavaScript的基本知识。
  • 对Node.js和Express.js有基本了解。
  • 熟悉MYSQL、POSTGRESQL、MSSQL、SQLite这些数据库中的任何一种。
  • 对Postman有基本了解,我们将用它来测试我们的端点。
  • 文本编辑器 - 我将使用VS Code。

在这篇文章中,我们将介绍你在使用sequelize时需要的功能,我们将使用基于项目的方法。

让我们开始吧!

项目设置

mkdir sequelize-project
cd sequelize-project

我们使用shell命令mkdir ,创建目录sequelize-project ,并使用cd 命令,导航到sequelize-project 文件夹。

下一步是启动一个Node.js应用程序。

npm init -y

这个命令将创建一个具有默认设置的package.json

{
  "name": "sequelize-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

设置express服务器

我们需要在安装Node.js服务器的同时安装express和一些软件包。

npm i express cors morgan dotenv nodemon cors

我们需要在sequelize-project 文件夹中创建app.js.env 文件。我们可以使用我们喜欢的编辑器来做这件事。

sequelize-project
├── .env
├── app.js
└── package.json

下一步是开始在我们的文件中添加必要的代码,我们将从下面开始.env

.env

我们将添加端口,如图所示。

PORT=5000

我们的node.js服务器将在这个端口上运行。

app.js

const express = require("express");
const cors = require("cors");
const morgan = require("morgan");

require("dotenv").config();
const port = process.env.PORT || 3000;

const app = express();

app.use(
  express.json({
    limit: "10mb",
  })
);

app.use(
  express.urlencoded({
    limit: "10mb",
    extended: false,
    parameterLimit: 10000,
  })
);

//Enable cors
app.use(cors());
app.use(morgan("common"));

app.get("/api", (req, res) => {
  const response = new Response(
    true,
    200,
    `Welcome to Sequelize Project ${port}`
  );
  res.status(response.code).json(response);
});

//Handling unhandle routes
app.all("*", (req, res, next) => {
  const response = new Response(
    false,
    404,
    `Page not found. Can't find ${req.originalUrl} on this server`
  );
  return res.status(response.code).json(response);
});

//listening to port
app.listen(port, () => {
  console.log(`Welcome to Sequelize Project running on port ${port}`);
});

上面的代码包含了使我们的node服务器成功运行的必要内容。

package.json
{
  "name": "sequelize-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon app.js",
    "start": "node app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "dotenv": "^10.0.0",
    "express": "^4.17.1",
    "morgan": "^1.10.0"
  }
}

我们添加了scripts 来运行Node.js服务器。

使用npm start ,我们将启动项目,但如果遇到错误,它将停止运行。而使用npm run dev ,即使遇到错误也会持续运行。

npm run dev 包含一个名为 的包,它帮助我们建立一个运行node文件的服务器。nodemon

让我们来运行这个应用程序。

npm run dev

安装sequelize

为了完全设置Sequelize,我们需要准备好数据库。它可以是MySQL、PostgreSQL、MSSQL或SQLite。

我们需要安装sequelizesequelize-cli

这些软件包将有助于引导我们在Node.js应用程序中对sequelize进行必要的设置。它将创建必要的文件、迁移和模型文件夹。

npm i sequelize sequelize-cli

然后,我们初始化它。

sequelize init

在初始化时,它将创建包含config.js 文件的config 文件夹,包含迁移的migrations 文件夹,包含模型的model 文件夹,包含种子文件的seeders 文件夹(如果有)。

现在,我们的项目文件结构应该是这样的。

sequelize-project
├── config
├── migrations
├── models
├── seeders
├── .env
├── app.js
└── package.json

下一步是决定我们要使用哪个数据库。你对数据库的选择将决定你需要安装的软件包。

  • MySQL -npm install mysql2
  • PostgreSQL -npm install pg
  • SQLite -npm install sqlite3
  • MSSQL -npm install tedious
  • MARIADB -npm install mariadb

在本教程中,让我们使用PostgreSQL。

我已经在PostgreSQL上创建了一个数据库,如图所示。

Database name - Sequelize
Database user - josh
Password - \***\*\*\*\*\***
Host - localhost

我们需要进入我们的.env 文件,将数据库的细节添加到其中。.env 文件的本质是使用process.env ,可以访问里面的所有细节。

另外,让我们创建一个.gitignore 文件,排除那些不需要推送到git仓库的文件。这里,我们排除了node_modules.env 文件。

现在,项目的文件结构应该是这样的。

sequelize-project
├── config
├── migrations
├── models
├── seeders
├── .env
├── .gitignore
├── app.js
└── package.json

.env 文件的内容。

PORT=5000
DATABASE_USER=josh
DATABASE_PASSWORD=password
DATABASE_NAME=sequelize
DATABASE_HOST=localhost
DATABASE_DIALECT=postgres
DATABASE_PORT=5432

数据库的默认端口。

MySQL (mysql) - `3306`
PostgreSQL (postgres) - `5432`
MSSQL (mssql) - `1433`
MARIADB (mariadb) - `3306`

下一步是将数据库凭证添加到配置文件夹内的config.json 文件中。

config.json 文件将不允许我们使用我们的.env 文件,我们将把它改名为config.js ,并添加下面的代码。

config.js

const dotenv = require("dotenv");
const path = require("path");

if (!process.env.HOST) {
  dotenv.config({
    path: path.join(__dirname, "..", ".env"),
  });
}

module.exports = {
  host: process.env.DATABASE_HOST,
  username: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  port: process.env.DATABASE_PORT,
  database: process.env.DATABASE_NAME,
  dialect: process.env.DATABASE_DIALECT,
};

接下来将是更新model 文件夹内的index.js ,如下图所示。

index.js

"use strict";
const fs = require("fs");
const path = require("path");
const Sequelize = require("sequelize");
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || "development";
const config = require(__dirname + "/../config/config.js");
const db = {};

// Initialize the sequelize object
let sequelize = new Sequelize({
  host: config.host,
  username: config.username,
  password: config.password,
  port: config.port,
  database: config.database,
  dialect: config.dialect,
});

// check database connection
sequelize
  .authenticate()
  .then(() => {
    console.log("success");
  })
  .catch((err) => {
    console.log(err);
  });

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

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

db.sequelize = sequelize;
module.exports = db;

上面的代码检查数据库连接是否成功或有错误。

如果连接成功,它将返回 "成功",否则它将以错误方式退出。

如果服务器目前正在运行,我们可以使用Ctrl + C 来停止它。

Executing (default): SELECT 1+1 AS result
success

如果我们正确地遵循了上述所有步骤,我们应该得到上述结果。

在了解了基础知识之后,让我们开始构建实际的项目。

创建模型

让我们建立一个用户模型,我们将使用sequelize-cli 命令来建立一个用户模型。

我们的用户将有一个firstName,lastName,age, 和任何其他需要的属性。

这把我们带到了Sequelize数据类型。我们在Sequelize中有不同的数据类型,如字符串、文本、整数、大数、浮点数、实数、双数、日期、布尔值,以及其他。

在创建我们的模型时,我们将需要指定我们模型的字段的数据类型。

让我们来创建我们的用户模型。

sequelize model:generate --name User --attributes firstName:string,lastName:string,age:integer

因此,一个新的model 和一个新的migration 将被创建。

现在,文件结构应该是这样的。

sequelize-project
├── config
├── migrations
|      ├── 20210727120010-create-user.js
├── models
|      ├── index.js
|      ├── user.js
├── seeders
├── .env
├── .gitignore
├── app.js
└── package.json

模型显示了我们正在使用的数据结构,而迁移是关于我们希望我们的数据在数据库中的结构的指示。

目前,我们的数据还没有反映在数据库中。为了实现这一点,我们需要运行我们的迁移。

每当我们创建一个模型或创建一个迁移时,我们都需要运行一个迁移,以便在数据库中反映出来。

sequelize db:migrate

输出。

== 20210727120010-create-user: migrating =======
== 20210727120010-create-user: migrated (0.350s)

运行上面的命令后,用户表已经在数据库中被创建,正如我们在.env 文件中所指定的那样。下一步是为节点服务器API创建一个services 文件夹。

我们将尝试使用sequelize,因为我们已经有了一个用户模型,我们将在我们的services 文件夹中创建一个user-service.js 文件。

现在,文件结构应该是这样的。

sequelize-project
├── config
├── migrations
|      ├── 20210727120010-create-user.js
├── models
|      ├── index.js
|      ├── user.js
├── seeders
├── services
|      ├── user-service.js
├── .env
├── .gitignore
├── app.js
└── package.json

将下面的代码添加到user-service.js

const User = require("../models/index")['User'];
class UserService { }

插入数据

当使用create方法时,数据在数据库中被创建。为了从模型中创建一个用户,我们使用sequelizecreate 方法。

如果我们向这个createUser 方法传递一个用户对象,它将在用户表中创建一个用户。

const User = require("../models/index")['User'];
class UserService {
    async createUser(user){
        return await User.create(user);
    }
}
let user = {
    firstName : "josh",
    lastName: "Ade",
    age: 20
}
let userService = new UserService();
const result = async() => {
    const data = await userService.createUser(user);
    console.log(data);
}
result();
async createUser(user) {
  return await User.create(user, {fields: ['firstName', 'lastName']});
}

上面的代码将不允许年龄被保存到数据库中,因为我们已经限制它只保存firstNamelastName

要测试这一点,请运行下面的代码。

node services/user-service.js

使用finder获取

这些finder方法在幕后使用SELECT 查询。

在sequelize中我们有大约5种方法用于查找操作。

  1. findAll
  2. findByPk
  3. findOne
  4. findOrCreate
  5. findAndCountAll
findAll

findAll 方法从我们正在处理的表中获取所有条目。在这里,它是用户表。

const User = require("../models/index")['User'];

class UserService {
    async findAllUser(){
        return await User.findAll();
    }
}
let userService = new UserService();
const result = async() => {
    const data = await userService.findAllUser();;
    console.log(data);
}

result();

我们不需要向它传递任何东西,User.findAll() 会给我们用户表中的所有用户。

为了测试这一点,运行下面的代码。

node services/user-service.js
findByPk

这使用主键来查找用户或你要找的等价物。

findByPk 方法会获取与我们作为参数传递的主键映射的记录。

在这里,主键默认为id 字段,该字段已经默认生成。

const User = require("../models/index")['User'];
class UserService {
    async findWithPk(userId){
        return await User.findByPk(userId);
    }
}
let userId = 1
let userService = new UserService();

const result = async() => {
    const data = await userService.findWithPk(userId);;
    console.log(data);
}

result();

为了测试这一点,运行下面的代码。

node services/user-service.js
findOne

根据我们传递的可选参数,它获取了第一个条目。

选项查询看起来像这样{where: { firstName: 'josh' }}

const User = require("../models/index")['User'];

class UserService {
    async findOne(firstname){
        return await User.findOne({where: {firstName: firstname}});
    }
}

let userService = new UserService();
let firstname = 'josh';
const result = async() => {
    const data = await userService.findOne(firstname);;
    console.log(data);
}

result();

要测试这个,请运行下面的代码。

node services/user-service.js
findOrCreate

根据我们传递的可选参数,获取条目或创建条目(如果它不存在)。

const User = require("../models/index")['User'];

class UserService {
  async findOrCreate(firstname){
      return await User.findOrCreate({where: {firstName: firstname},
      defaults: {
          lastName: 'Unknown',
      }
    });
  }
}

let userService = new UserService();
let firstname = 'josh';
const result = async() => {
  const data = await userService.findOrCreate(firstname);;
  console.log(data);
}

result();

要测试这个,请运行下面的代码。

node services/user-service.js
findAndCountAll

这个方法是findAllcount 方法的组合。

它可以找到所有的条目,并在结果中加入计数。

const User = require("../models/index")['User'];

class UserService {
  async findOrCreate(firstname){
      return await User.findOrCreate({where: {firstName: firstname},
      defaults: {
          lastName: 'Unknown',
      }
    });
  }
}

let userService = new UserService();
let firstname = 'josh';
const result = async() => {
  const data = await userService.findOrCreate(firstname);;
  console.log(data);
}

result();

要测试这一点,请运行下面的代码。

node services/user-service.js

更新

这个方法可以用来更新现有的数据。

const User = require("../models/index")['User'];
class UserService {
    async updateUser(id, payload) {
    return await User.update(payload, {
      where: {
        id
      }
    });
  }
}

let userService = new UserService();
let payload = {
    firstName : "joshua"
};
let id = 1;
const result = async() => {
  const data = await userService.update(id, payload);;
  console.log(data);
}

result();

要测试这一点,请运行下面的代码。

node services/user-service.js

删除

这个方法可以用来删除现有的数据。

const User = require("../models/index")['User'];
class UserService {
  async deleteUser(id){
        return await User.destroy({
             where: {
                id
            }
        });
    }
}

let userService = new UserService();
let id = 1;
const result = async() => {
  const data = await userService.deleteUser(id);;
  console.log(data);
}

result();

要测试这一点,请运行下面的代码。

node services/user-service.js

关联

关联指的是不同表之间的关系。当一个表使用引用另一个表的主键的外键时,一个关系可以在表之间建立。

主键是一个特定表的唯一标识符,而外键是在执行关联时与另一个表的主键相连的字段。

这就是关系型数据库背后的概念。

有三种主要的关系类型。

  1. 一对一
  2. 一对多
  3. 多对多

一对一关联

这种关联指的是当一个特定表中的记录与另一个表的另一个记录相关联。一个典型的例子是,用户表中的一个userId ,只能与profile表中的一个用户资料相关联。

我们需要两个表来展示这个工作原理,我们已经从我们的用户模型中创建了一个用户表,让我们来创建一个配置文件表。

这是个练习创建模型的机会。

sequelize model:generate --name Profile --attributes height:string,country:string,email:string,userId:integer

我们将得到一个结果:一个新的模型和一个新的迁移已经被创建。

每当我们创建一个模型或创建一个迁移时,我们都需要运行一个迁移,以使它反映在数据库中。

sequelize db:migrate

输出。

== 20211022092823-create-profile: migrating =======
== 20211022092823-create-profile: migrated (0.147s)

我们需要进入models/profile.js ,将我们的userId 作为主键并设置关联。在这个例子中,它是Profile.hasOne(User)

models/profile.js

"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class Profile extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      Profile.hasOne(models.User, {
        foreignKey: "id",
        as: "user",
      });
    }
  }
  Profile.init(
    {
      height: DataTypes.STRING,
      country: DataTypes.STRING,
      email: DataTypes.STRING,
      userId: { type: DataTypes.INTEGER, primaryKey: true },
    },
    {
      sequelize,
      modelName: "Profile",
    }
  );
  return Profile;
};

我们将userId 作为主键。我们还将Profile模型与User模型关联,并引用了User模型的外键。

我们需要在我们的服务文件夹内创建一个profile-service.js 文件。

services/profile-service.js

const Profile = require("../models/index")['Profile'];
const User = require("../models/index")['User'];

class ProfileService {
    async createProfile(profile){
        return await Profile.create(profile);
    }
    async getAll(){
        return await Profile.findAll({
            include: [
                {
                    model: User,
                    as: 'user',
                },
            ],
        });
    }
}

let profileService = new ProfileService();
let profile = {
    userId : 1,
    height: "30",
    country: "Nigeria",
    email: "ade@yahoo.com"
}

const result = async() => {
   let dataCreated = await profileService.createProfile(profile);
   let data = await profileService.getAll();
}

result();

这里需要注意的是,userId 指向一个现有的用户。另一件要注意的事情是,"include "包含了我们试图与之关联的模型。

为了测试这一点,运行下面的代码。

node services/profile-service.js

在我们的profileService ,我们有createProfilegetAll 方法,它们被用来为一个用户创建一个配置文件,另一个则是获取数据库中所有的配置文件。

一个配置文件的示例结果看起来像这样。

{
  height: '30',
  country: 'Nigeria',
  email: 'ade@yahoo.com',
  userId: 1,
  createdAt: 2021-10-22T14:03:35.372Z,
  updatedAt: 2021-10-22T14:03:35.372Z,
  user: [User]
}

user 属性包含用户信息。

我们可以从另一个表中获得相关信息。该属性名称来自我们在profile Model中使用的'as'。

你也可以使用上面的方法将用户与用户模型中的profile关联起来。

一对多关联

这种关联指的是,当一个特定表中的记录与另一个表中的一个以上的记录相关联,一个典型的例子是,用户表中的一个userId ,可以与汽车表中的许多汽车相关联。

我们需要两个表来展示这个工作原理,我们已经从我们的用户模型中创建了一个用户表,让我们创建一个汽车表。

sequelize model:generate --name Cars --attributes color:string,name:string,userId:integer

我们将得到一个结果,一个新的模型和一个新的迁移已经被创建。每当我们创建一个模型或创建一个迁移时,我们都需要运行一个迁移,以便在数据库中反映出来。

sequelize db:migrate
== 20211023110522-create-cars: migrating =======
== 20211023110522-create-cars: migrated (0.606s)

我们需要进入models/cars.js ,将我们的userId 作为主键,我们也可以决定为汽车设置一个一对一的主键。这意味着一辆车只能有一个用户Cars.hasOne(user)

models/cars.js

"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class Cars extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      Cars.hasOne(models.User, {
        foreignKey: "id",
        as: "user",
      });
    }
  }
  Cars.init(
    {
      color: DataTypes.STRING,
      name: DataTypes.STRING,
      userId: { type: DataTypes.INTEGER, primaryKey: true },
    },
    {
      sequelize,
      modelName: "Cars",
    }
  );
  return Cars;
};

为了显示一对多的关系,我们需要进入models/user.js 并添加user.hasMany(cars)

models/user.js

"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class User extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      User.hasOne(models.Profile, {
        foreignKey: "userId",
        as: "profile",
      });

      User.hasMany(models.Cars, {
        foreignKey: "userId",
        as: "cars",
      });
    }
  }
  User.init(
    {
      firstName: DataTypes.STRING,
      lastName: DataTypes.STRING,
      age: DataTypes.INTEGER,
    },
    {
      sequelize,
      modelName: "User",
    }
  );
  return User;
};

我们需要在我们的服务文件夹中创建一个cars-service.js 文件。我们将在这个文件中创建新的汽车,记住,这些汽车将附属于一个用户。

services/cars-service.js

const User = require("../models/index")["User"];
const Cars = require("../models/index")["Cars"];

class CarService {
  async createCar(car) {
    return await Cars.create(car);
  }
}

let carService = new CarService();
let car = {
  userId: 1,
  color: "blue",
  name: "Toyota Camry",
};
const result = async () => {
  let data = await profileService.createProfile(profile);
  console.log(data);
};

result();

为了测试这一点,运行下面的代码。

node services/cars-service.js

我们已经成功地创建了我们的汽车,我建议你创建一个以上的汽车,这样你就可以看到一对多的关联行动了。

我们将进入我们的用户服务文件以获得所有的用户,我们应该有汽车的属性显示属于每个用户的所有汽车。

services/user-service.js

const User = require("../models/index")["User"];
const Profile = require("../models/index")["Profile"];
const Cars = require("../models/index")["Cars"];

class UserService {
  async findByPk(userId) {
    return await User.findByPk(userId);
  }

  async findAll() {
    return await User.findAll({
      include: [
        {
          model: Cars,
          as: "cars",
        },
      ],
    });
  }
}

let userService = new UserService();
const result = async () => {
  let data = await userService.findAll();
  console.log(data);
};

result();

为了测试这一点,运行下面的代码。

node services/user-service.js

用户数据的样本结果应该是这样的。

{
  id: 1,
  firstName: 'josh',
  lastName: 'Ade',
  age: 20,
  createdAt: 2021-10-22T09:01:48.170Z,
  updatedAt: 2021-10-22T09:01:48.170Z,
  profile: null,
  cars: [Array]
}

这里的关键是,汽车的属性将包含一个汽车的数组。这意味着无论何时你查询一个用户或所有用户,他们也将显示 "许多 "汽车,如果我们有一个以上的相关汽车。如果用户没有车,它将返回一个空数组。

多对多关联

这种关联指的是当一个特定表中的许多记录与另一个表中的许多记录相关联。

我们有两张表,演员表和电影表。一个演员可以出现在多个电影中,一个电影可以有多个演员。

说真的,这看起来很混乱,我们如何跟踪这个,这听起来像是一个双向的一对多关系。唯一的区别是,两边都没有一个唯一的记录,所以我们需要一个额外的表来跟踪演员和电影,我们把这个表叫做movieactor。

这个表的本质是,每创建一部电影,我们就可以为它添加许多演员,每创建一个演员,我们就可以添加一部电影。

在这一点上,让我们回到编码上。

我们需要创建3个表,演员、电影、movieactor。

sequelize model:generate --name Actor --attributes name:string
sequelize model:generate --name Movie --attributes name:string
sequelize model:generate --name MovieActor --attributes MovieId:integer,ActorId:integer

运行迁移。

sequelize db:migrate

我们所有的模型都已经被创建,表也已经被添加到数据库中。

我们需要更新movie和actor的模型。

models/actor.js

"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class Actor extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      Actor.belongsToMany(models.Movie, {
        through: models.MovieActor,
        as: "movies",
        foreignKey: "MovieId",
      });
    }
  }
  Actor.init(
    {
      name: DataTypes.STRING,
    },
    {
      sequelize,
      modelName: "Actor",
    }
  );
  return Actor;
};

对于多对多的关系,我们使用了belongsToMany ,我们有像Movie.belongsToMany(Actor)

我们还添加了through属性,它指向了MovieActor 模型。我们已经解决了一对一和一对多中的其他属性。

models/movie.js

"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class Movie extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      Movie.belongsToMany(models.Actor, {
        through: models.MovieActor,
        as: "actors",
        foreignKey: "ActorId",
      });
    }
  }
  Movie.init(
    {
      name: DataTypes.STRING,
    },
    {
      sequelize,
      modelName: "Movie",
    }
  );
  return Movie;
};

我们不需要向MovieActor模型添加任何东西。

现在,我们需要创建movie-service.jsactor-service.js

services/actor-service.js

const Actor = require("../models/index")['Actor'];
const User = require("../models/index")['User'];

class ActorService {
    async createActor(actor){
        return await Actor.create(actor);
    }
}

let actorService = new ActorService();
let actor = {
    name : "Josh",
}
const result = async() => {
   let data = await actorService.createActor(actor);
    console.log(data);
}

result();

为了测试这一点,运行下面的代码。

node services/actor-service.js

actor-service.js ,我们创建了一个演员,我们将需要在movie-service中创建这个演员来解释多对多,那么你也可以在actor-service中复制多对多。

services/movie-service.js

const Movie = require("../models/index")['Movie'];
const Actor = require("../models/index")['Actor'];
const User = require("../models/index")['User'];

class MovieService {
  async createMovie(movie){
      return await Movie.create(movie);
  }
  async findOneMovie(id){
    return await Movie.findOne({
      where : {
          id
      },
      include: [
          {
              model: Actor,
              as: 'actors',
          },
      ],
    })
  }
}


let movieService = new MovieService();
let newMovie = {
    name : "Titanic",
}

const result = async() => {
  let movie = await movieService.createMovie(NewMovie);
  let actor = await Actor.findOne({where : {id: 1}})
  let data = await movie.addActor(actor);
  let oneMovie = await movieService.findOneMovie(1)
  console.log(oneMovie);
}

result();

为了测试这一点,运行下面的代码。

node services/movie-service.js

这里唯一的新东西是addActor 方法。多对多的关系使模型可以访问addMovieaddActor 等方法。

就像我们可以从Movie 模型访问addActor ,我们也可以从Actor 模型访问addMovie

因此,在创建一个电影之后,如果演员已经被创建,你可以把演员添加到电影中。当我们通过findOne movie或findAll ,得到这部电影时,我们会看到一个数组,里面有所有附在这部电影上的演员。

这与我们在一对多关系中看到的情况类似。

总结

到目前为止,我们已经学会了。

  • 如何安装Sequelize。
  • 如何安装与不同数据库相关的驱动程序。
  • 连接到数据库并测试连接。
  • 如何使用Sequelize CLI。
  • 使用Sequelize的CRUD操作。
  • 数据库关联性。