Использование Sequelize для выполнения запроса к объединенной таблице в EggJS

Egg.js

[Для пересылки укажите источник] Адрес личного блога:Кодовые заметки маленькой обезьянки

1. EggJS ссылается на Sequelize

  1. Установите дополнительные зависимости и драйвер mysql.

    cnpm i egg-sequelize mysql2 -S
    
  2. Включить плагин продолжения

    Добавьте в config/plugin.js

    sequelize: {
        enable: true,
        package: 'egg-sequelize',
    },
    
  3. база данных конфигурации

    Добавьте в config/config.default.js

    config.sequelize = {
        dialect: 'mysql',  // 表示使用mysql
        host: '127.0.0.1', // 连接的数据库主机地址
        port: 3306, // mysql服务端口
        database: 'demo', // 数据库名
        username: 'root',  // 数据库用户名
        password: 'root', // 数据库密码
        define: {  // model的全局配置
          	timestamps: true,   // 添加create,update,delete时间戳
          	paranoid: true,   // 添加软删除
          	freezeTableName: true,  // 防止修改表名为复数
          	underscored: false  // 防止驼峰式字段被默认转为下划线
        },
        timezone: '+8:00',  // 由于orm用的UTC时间,这里必须加上东八区,否则取出来的时间相差8小时
        dialectOptions: {  // 让读取date类型数据时返回字符串而不是UTC时间
            dateStrings: true,
            typeCast(field, next) {
                if (field.type === "DATETIME") {
                    return field.string();
                }
                return next();
            }
        }
    };
    

2. Определите модель

  1. Проект Egg, созданный с помощью egg-init, в начале не имеет каталога app/model.Первоначальная структура проекта выглядит следующим образом:

    itzishu
    ├── README.md
    ├── app
    │   ├── controller
    │   │   └── home.js
    │   └── router.js
    ├── appveyor.yml
    ├── config
    │   ├── config.default.js
    │   └── plugin.js
    ├── package.json
    └── test
        └── app
            └── controller
                └── home.test.js
    

    Во-первых, создайте новый каталог в каталоге приложения с именем model, который используется для хранения содержимого объекта экземпляра всех таблиц, определенных в базе данных.

  2. Содержимое таблицы базы данных следующее:

    /*
     Navicat Premium Data Transfer
    
     Source Server         : 系统数据库3306
     Source Server Type    : MySQL
     Source Server Version : 50725
     Source Host           : localhost:3306
     Source Schema         : demo
    
     Target Server Type    : MySQL
     Target Server Version : 50725
     File Encoding         : 65001
    
     Date: 12/05/2019 15:11:37
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for classes
    -- ----------------------------
    DROP TABLE IF EXISTS `classes`;
    CREATE TABLE `classes` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(50) NOT NULL,
      `createdAt` datetime DEFAULT NULL,
      `updatedAt` datetime DEFAULT NULL,
      `deletedAt` datetime DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
    
    -- ----------------------------
    -- Records of classes
    -- ----------------------------
    BEGIN;
    INSERT INTO `classes` VALUES (1, '软件工程1601', '2019-05-12 13:11:43', '2019-05-12 13:11:47', NULL);
    INSERT INTO `classes` VALUES (2, '网络工程1601', '2019-05-12 13:12:10', '2019-05-12 13:12:13', NULL);
    COMMIT;
    
    -- ----------------------------
    -- Table structure for info
    -- ----------------------------
    DROP TABLE IF EXISTS `info`;
    CREATE TABLE `info` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(50) NOT NULL,
      `age` int(11) NOT NULL,
      `sex` tinyint(255) NOT NULL DEFAULT '1' COMMENT '1为男,0为女',
      `studentId` int(11) NOT NULL,
      `createdAt` datetime DEFAULT NULL,
      `updatedAt` datetime DEFAULT NULL,
      `deletedAt` datetime DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
    
    -- ----------------------------
    -- Records of info
    -- ----------------------------
    BEGIN;
    INSERT INTO `info` VALUES (1, '许仙', 23, 1, 1, '2019-05-12 13:25:58', '2019-05-12 13:26:01', NULL);
    INSERT INTO `info` VALUES (2, '白素贞', 20, 0, 2, '2019-05-12 13:26:41', '2019-05-12 13:26:46', NULL);
    INSERT INTO `info` VALUES (3, '法海', 22, 1, 3, '2019-05-12 13:27:20', '2019-05-12 13:27:22', NULL);
    INSERT INTO `info` VALUES (4, '小青', 18, 0, 4, '2019-05-12 13:27:48', '2019-05-12 13:27:51', NULL);
    INSERT INTO `info` VALUES (5, '金如意', 20, 0, 5, '2019-05-12 13:28:34', '2019-05-12 13:28:37', NULL);
    INSERT INTO `info` VALUES (6, '景松', 23, 1, 6, '2019-05-12 13:30:07', '2019-05-12 13:30:10', NULL);
    COMMIT;
    
    -- ----------------------------
    -- Table structure for lession
    -- ----------------------------
    DROP TABLE IF EXISTS `lession`;
    CREATE TABLE `lession` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(50) NOT NULL,
      `createdAt` datetime DEFAULT NULL,
      `updatedAt` datetime DEFAULT NULL,
      `deletedAt` datetime DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
    
    -- ----------------------------
    -- Records of lession
    -- ----------------------------
    BEGIN;
    INSERT INTO `lession` VALUES (1, '计算机网络', '2019-05-12 13:12:32', '2019-05-12 13:12:35', NULL);
    INSERT INTO `lession` VALUES (2, 'Java程序设计', '2019-05-12 13:12:50', '2019-05-12 13:12:52', NULL);
    INSERT INTO `lession` VALUES (3, '软件项目管理', '2019-05-12 13:13:07', '2019-05-12 13:13:10', NULL);
    INSERT INTO `lession` VALUES (4, '网络安全', '2019-05-12 13:13:22', '2019-05-12 13:13:25', NULL);
    COMMIT;
    
    -- ----------------------------
    -- Table structure for lession_student
    -- ----------------------------
    DROP TABLE IF EXISTS `lession_student`;
    CREATE TABLE `lession_student` (
      `lessionId` int(11) NOT NULL,
      `studentId` int(11) NOT NULL,
      `createdAt` datetime DEFAULT NULL,
      `updatedAt` datetime DEFAULT NULL,
      `deletedAt` datetime DEFAULT NULL,
      PRIMARY KEY (`lessionId`,`studentId`) USING BTREE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- ----------------------------
    -- Records of lession_student
    -- ----------------------------
    BEGIN;
    INSERT INTO `lession_student` VALUES (1, 1, '2019-05-12 13:20:35', '2019-05-12 13:20:40', NULL);
    INSERT INTO `lession_student` VALUES (1, 2, '2019-05-12 13:20:51', '2019-05-12 13:20:53', NULL);
    INSERT INTO `lession_student` VALUES (1, 3, '2019-05-12 13:21:02', '2019-05-12 13:21:05', NULL);
    INSERT INTO `lession_student` VALUES (1, 4, '2019-05-12 13:21:15', '2019-05-12 13:21:19', NULL);
    INSERT INTO `lession_student` VALUES (1, 5, '2019-05-12 13:21:29', '2019-05-12 13:21:32', NULL);
    INSERT INTO `lession_student` VALUES (1, 6, '2019-05-12 13:21:43', '2019-05-12 13:21:45', NULL);
    INSERT INTO `lession_student` VALUES (2, 1, '2019-05-12 13:23:10', '2019-05-12 13:23:13', NULL);
    INSERT INTO `lession_student` VALUES (2, 3, '2019-05-12 13:23:28', '2019-05-12 13:23:31', NULL);
    INSERT INTO `lession_student` VALUES (2, 4, '2019-05-12 13:23:40', '2019-05-12 13:23:43', NULL);
    INSERT INTO `lession_student` VALUES (2, 5, '2019-05-12 13:23:54', '2019-05-12 13:23:57', NULL);
    INSERT INTO `lession_student` VALUES (3, 1, '2019-05-12 13:24:21', '2019-05-12 13:24:24', NULL);
    INSERT INTO `lession_student` VALUES (3, 4, '2019-05-12 13:24:39', '2019-05-12 13:24:42', NULL);
    INSERT INTO `lession_student` VALUES (4, 2, '2019-05-12 13:24:59', '2019-05-12 13:25:03', NULL);
    INSERT INTO `lession_student` VALUES (4, 6, '2019-05-12 13:25:12', '2019-05-12 13:25:15', NULL);
    COMMIT;
    
    -- ----------------------------
    -- Table structure for student
    -- ----------------------------
    DROP TABLE IF EXISTS `student`;
    CREATE TABLE `student` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `number` varchar(12) NOT NULL COMMENT '学号',
      `password` varchar(32) NOT NULL,
      `classId` int(11) NOT NULL,
      `createdAt` datetime DEFAULT NULL,
      `updatedAt` datetime DEFAULT NULL,
      `deletedAt` datetime DEFAULT NULL,
      PRIMARY KEY (`id`,`number`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
    
    -- ----------------------------
    -- Records of student
    -- ----------------------------
    BEGIN;
    INSERT INTO `student` VALUES (1, '160101', '202cb962ac59075b964b07152d234b70', 1, '2019-05-12 13:16:09', '2019-05-12 13:16:12', NULL);
    INSERT INTO `student` VALUES (2, '160201', '202cb962ac59075b964b07152d234b70', 2, '2019-05-12 13:16:32', '2019-05-12 13:16:35', NULL);
    INSERT INTO `student` VALUES (3, '160102', '202cb962ac59075b964b07152d234b70', 1, '2019-05-12 13:17:17', '2019-05-12 13:17:21', NULL);
    INSERT INTO `student` VALUES (4, '160103', '202cb962ac59075b964b07152d234b70', 1, '2019-05-12 13:17:51', '2019-05-12 13:17:54', NULL);
    INSERT INTO `student` VALUES (5, '160104', '202cb962ac59075b964b07152d234b70', 1, '2019-05-12 13:18:13', '2019-05-12 13:18:16', NULL);
    INSERT INTO `student` VALUES (6, '160202', '202cb962ac59075b964b07152d234b70', 2, '2019-05-12 13:18:36', '2019-05-12 13:18:39', NULL);
    COMMIT;
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    

    Среди них отношения между каждой таблицей:

    • Существует связь один к одному между учеником и информацией.
    • Между классами и учениками существует связь «один ко многим».
    • Между студентом и уроком существует отношение «многие ко многим», а промежуточная таблица — это урок_студента.
  3. По структуре таблицы данных определяем взаимосвязь и записываем соответствующие файлы в директорию модели

    • student.js
    module.exports = app => {
        const { STRING, INTEGER } = app.Sequelize;
    
        const Student = app.model.define('student', {
            id: {
                type: INTEGER,
                autoIncrement: true,
                primaryKey: true
            },
            number: {
                type: STRING,
                allowNull: false,
            },
            password: {
                type: STRING(32),
                allowNull: false
            },
            classId: {
                type: INTEGER,
                allowNull: false
            }
        });
    
        Student.associate = function (){
            // 与Info存在一对多关系,所以是hasOne()
            app.model.Student.hasOne(app.model.Info, {foreignKey: 'studentId'});
            // 与Classes存在多对一关系,所以使用belongsTo()
            app.model.Student.belongsTo(app.model.Classes, {foreignKey: 'classId', targetKey: 'id'});
            // 与Lessison存在多对多关系,使用belongsToMany()
            app.model.Student.belongsToMany(app.model.Lession, {
                through: app.model.LessionStudent,
                foreignKey: 'studentId',
                otherKey: 'lessionId'
            });
        }
    
        return Student;
    }
    
    • info.js
    module.exports = app => {
        const { STRING, INTEGER, BOOLEAN } = app.Sequelize;
    
        const Info = app.model.define('info', {
            id: {
                type: INTEGER,
                autoIncrement: true,
                primaryKey: true
            },
            name: {
                type: STRING(50),
                allowNull: false,
            },
            age: {
                type: INTEGER,
                allowNull: false
            },
            sex: {
                type: BOOLEAN,
                allowNull: false,
                get() {
                    if ( this.getDataValue('sex') ){
                        return '男';
                    }else {
                        return '女';
                    }
                }
            },
            studentId: {
                type: INTEGER,
                allowNull: false
            }
        });
    
        Info.associate = function (){
            app.model.Info.belongsTo(app.model.Student, {foreignKey: 'studentId', targetKey: 'id'});
        }
    
        return Info;
    }
    

    Обратите внимание, что в поле пола есть метод get(){}, потому что в таблице данных поле пола хранит 1 или 0, 1 — мужчина, а 0 — женщина, чтобы напрямую вернуть «мужской» или « female», здесь метод get используется для обработки данных после нахождения данных, а данные, возвращаемые в вызываемую функцию, — это значение, которое мы установили

    • classes.js
    module.exports = app => {
        const { STRING, INTEGER, BOOLEAN } = app.Sequelize;
    
        const Classes = app.model.define('classes', {
            id: {
                type: INTEGER,
                autoIncrement: true,
                primaryKey: true
            },
            name: {
                type: STRING(50),
                allowNull: false,
            },
            age: {
                type: INTEGER,
                allowNull: false
            },
            sex: {
                type: BOOLEAN,
                allowNull: false,
                get() {
                    if ( this.getDataValue('sex') ){
                        return '男';
                    }else {
                        return '女';
                    }
                }
            },
            studentId: {
                type: INTEGER,
                allowNull: false
            }
        });
    
        Classes.associate = function (){
            // classes与student是一对多关系,所以这里使用hasMany()
            app.model.Classes.hasMany(app.model.Student, {foreignKey: 'classId', targetKey: 'id'});
        }
    
        return Classes;
    }
    
    • lession.js
    module.exports = app => {
        const { INTEGER, STRING } = app.Sequelize;
    
        const Lession = app.model.define('lession', {
            id: {
                type: INTEGER,
                primaryKey: true,
                autoIncrement: true
            },
            name: {
                type: STRING,
                allowNull: false
            }
        });
    
        Lession.associate = function(){
            // 与student表是多对多关系
            app.model.Lession.belongsToMany(app.model.Student, {
                through: app.model.LessionStudent,
                foreignKey: 'lessionId',
                otherKey: 'studentId'
            });
        }
    
        return Lession;
    }
    
    • lession-student.js
    module.exports = app => {
        const { INTEGER } = app.Sequelize;
    
        const LessionStudent = app.model.define('lession_student', {
            lessionId: {
                type: INTEGER,
                primaryKey: true
            },
            studentId: {
                type: INTEGER,
                primaryKey: true
            }
        });
    
        LessionStudent.associate = function(){
    
        }
    
        return LessionStudent;
    }
    
  4. Кратко опишите, что определяет Модель

    • Общие типы полей для MYSQL

    Тип поля получен из app.Sequelize, а соответствующее имя выглядит следующим образом.

    Sequelize.STRING                      // VARCHAR(255)
    Sequelize.STRING(1234)                // VARCHAR(1234)
    Sequelize.STRING.BINARY               // VARCHAR BINARY
    Sequelize.TEXT                        // TEXT
    Sequelize.TEXT('tiny')                // TINYTEXT
    
    Sequelize.INTEGER                     // INTEGER
    Sequelize.BIGINT                      // BIGINT
    Sequelize.BIGINT(11)                  // BIGINT(11)
    
    Sequelize.FLOAT                       // FLOAT
    Sequelize.FLOAT(11)                   // FLOAT(11)
    Sequelize.FLOAT(11, 12)               // FLOAT(11,12)
    
    Sequelize.DOUBLE                      // DOUBLE
    Sequelize.DOUBLE(11)                  // DOUBLE(11)
    Sequelize.DOUBLE(11, 12)              // DOUBLE(11,12)
    
    Sequelize.DECIMAL                     // DECIMAL
    Sequelize.DECIMAL(10, 2)              // DECIMAL(10,2)
    
    Sequelize.DATE                        // DATETIME 针对 mysql / sqlite, TIMESTAMP WITH TIME ZONE 针对 postgres
    Sequelize.DATE(6)                     // DATETIME(6) 针对 mysql 5.6.4+. 小数秒支持多达6位精度
    Sequelize.DATEONLY                    // DATE 不带时间.
    Sequelize.BOOLEAN                     // TINYINT(1)
    

    Ссылки на типы, разрешенные другими базами данных:тип данных

    • Значение свойства поля
    Имя свойства тип По умолчанию инструкция инструкция
    type Any никто да тип данных
    primaryKey Boolean false нет первичный ключ
    autoIncrement Boolean false нет автоматическое приращение
    allowNull Boolean false нет Можно ли быть пустым
    defaultValue Any никто нет По умолчанию
    field String имя поля нет имя пользовательского поля
    unique Any никто нет ограничение
    • ассоциация между таблицами

    В продолжении существует три типа связей между таблицами с точки зрения кода: один-к-одному, один-ко-многим и многие-ко-многим.

    1. один на один

      В этом проекте между таблицей учащегося и информационной таблицей существует отношение один к одному, и учащийся имеет эксклюзивную часть информации.

      В student.js используется метод hasOne().Первым параметром является связанный с моделью объект Info, а вторым параметром является объект, который содержит атрибут, foreginKey которого является полем studentId в соответствующей информационной таблице.

      В info.js используется метод ownTo().Первым параметром является связанный с моделью объект Student, а вторым параметром также является объект с двумя свойствами.ForeginKey — это поле "studentId" в информационной таблице.Второй параметр targetKey — это поле «id» в таблице учеников.

      Резюме: первый параметр hasOne () и ownTo () — это экземпляр модели другой таблицы, связанной с этой таблицей. Во втором параметре есть атрибут foreginKey. Для hasOne значение этого атрибута является идентификатором другой таблицы и Соответствующее поле, для принадлежности к этому атрибуту значением является имя поля в этой таблице, соответствующее идентификатору противоположной таблицы. ownTo имеет на один атрибут targetKey больше, чем hasOne, который является соответствующим именем первичного ключа противоположной таблицы.

    2. один ко многим

      Между классами и учащимися существует связь «один ко многим» В классе есть несколько учеников, и несколько учеников образуют класс.

      В student.js используется createdTo(), а в class.js используется hasMany().Обнаружено, что параметры, требуемые hasMany() и ownTo(), аналогичны, но здесь обратите внимание, что foreginKey в hasMany( ) Значением является classId таблицы-аналога. Объединив приведенный выше анализ «один к одному», мы можем сделать вывод:

      В методе, начинающемся с has, значение атрибута foreginKey находится в таблице другой стороны, и если есть значение targetKey, это его собственный первичный ключ;

      В методе в начале принадлежности значение атрибута foreginKey находится в собственной таблице, а значение атрибута targetKey — это значение другой таблицы.

    3. многие ко многим

      Чтобы проанализировать отношения «многие ко многим», у учащегося есть несколько курсов, а у курса несколько студентов, мы можем использовать промежуточную таблицу Lession-student.js для установления этой связи.

      В student.js мы используем метод ownToMany (), и то же самое верно в файле Lession.js, Через содержимое параметра этого метода мы можем обнаружить, что есть дополнительный сквозной атрибут, значением которого является экземпляр Model для промежуточная таблица. Согласно вышеизложенным правилам, в методе в начале owns foreginKey находит себя, а otherKey находит другие, поэтому его легко понять.

    Резюме: в экземпляре модели переопределите ассоциированный метод модели и поместите в него связанную связь.

    Индивидуальные методы:hasOne(Model, {foreignKey:对方,})иbelongsTo(Model,{foreignKey:自己,targetKey:对方})

    Методы «один ко многим»:hasMany(Model,{foreignKey:对方, targetKey:自己})иbelongsTo(Model,{foreignKey:自己,targetKey:对方})

    Методы «многие ко многим»:belongsToMany(Model,{through:Model, targetKey:自己, otherKey:对方})

3. Запрос к объединенной таблице

  • один на один

    Напишите в контроллере следующее

    // 获取学生信息 通过一对多的联系
        async info(){
            const { ctx, app } = this;
            let result = await app.model.Student.findAll({
              include: {
                model: app.model.Info
              }
            });
            ctx.body = result;
        }
    

    Полученные значения следующие:

    [
    		// 第一个学生
        {
            "id": 1,
            "number": "160101",
            "password": "202cb962ac59075b964b07152d234b70",
            "classId": 1,
            "createdAt": "2019-05-12 13:16:09",
            "updatedAt": "2019-05-12 13:16:12",
            "deletedAt": null,
            "info": {  // 联表查到的信息
                "sex": "男",
                "id": 1,
                "name": "许仙",
                "age": 23,
                "studentId": 1,
                "createdAt": "2019-05-12 13:25:58",
                "updatedAt": "2019-05-12 13:26:01",
                "deletedAt": null
            }
        },
      	// 第二个学生
        {
            "id": 2,
            "number": "160201",
            "password": "202cb962ac59075b964b07152d234b70",
            "classId": 2,
            "createdAt": "2019-05-12 13:16:32",
            "updatedAt": "2019-05-12 13:16:35",
            "deletedAt": null,
            "info": {
                "sex": "女",
                "id": 2,
                "name": "白素贞",
                "age": 20,
                "studentId": 2,
                "createdAt": "2019-05-12 13:26:41",
                "updatedAt": "2019-05-12 13:26:46",
                "deletedAt": null
            }
        },
        {
            "id": 3,
            "number": "160102",
            "password": "202cb962ac59075b964b07152d234b70",
            "classId": 1,
            "createdAt": "2019-05-12 13:17:17",
            "updatedAt": "2019-05-12 13:17:21",
            "deletedAt": null,
            "info": {
                "sex": "男",
                "id": 3,
                "name": "法海",
                "age": 22,
                "studentId": 3,
                "createdAt": "2019-05-12 13:27:20",
                "updatedAt": "2019-05-12 13:27:22",
                "deletedAt": null
            }
        },
        {
            "id": 4,
            "number": "160103",
            "password": "202cb962ac59075b964b07152d234b70",
            "classId": 1,
            "createdAt": "2019-05-12 13:17:51",
            "updatedAt": "2019-05-12 13:17:54",
            "deletedAt": null,
            "info": {
                "sex": "女",
                "id": 4,
                "name": "小青",
                "age": 18,
                "studentId": 4,
                "createdAt": "2019-05-12 13:27:48",
                "updatedAt": "2019-05-12 13:27:51",
                "deletedAt": null
            }
        },
        {
            "id": 5,
            "number": "160104",
            "password": "202cb962ac59075b964b07152d234b70",
            "classId": 1,
            "createdAt": "2019-05-12 13:18:13",
            "updatedAt": "2019-05-12 13:18:16",
            "deletedAt": null,
            "info": {
                "sex": "女",
                "id": 5,
                "name": "金如意",
                "age": 20,
                "studentId": 5,
                "createdAt": "2019-05-12 13:28:34",
                "updatedAt": "2019-05-12 13:28:37",
                "deletedAt": null
            }
        },
        {
            "id": 6,
            "number": "160202",
            "password": "202cb962ac59075b964b07152d234b70",
            "classId": 2,
            "createdAt": "2019-05-12 13:18:36",
            "updatedAt": "2019-05-12 13:18:39",
            "deletedAt": null,
            "info": {
                "sex": "男",
                "id": 6,
                "name": "景松",
                "age": 23,
                "studentId": 6,
                "createdAt": "2019-05-12 13:30:07",
                "updatedAt": "2019-05-12 13:30:10",
                "deletedAt": null
            }
        }
    ]
    
  • один ко многим

    // 获取班级名为 软件工程1601 的班级学生
        async student(){
          const { ctx, app } = this;
          let result = await app.model.Classes.findAll({
            where: {
              name: '软件工程1601'
            },
            include: {
              model: app.model.Student
            }
          })
          ctx.body = result;
        }
    

    Получите данные следующим образом:

    [
        {
            "id": 1,
            "name": "软件工程1601",
            "createdAt": "2019-05-12 13:11:43",
            "updatedAt": "2019-05-12 13:11:47",
            "deletedAt": null,
            "students": [
                {
                    "id": 1,
                    "number": "160101",
                    "password": "202cb962ac59075b964b07152d234b70",
                    "classId": 1,
                    "createdAt": "2019-05-12 13:16:09",
                    "updatedAt": "2019-05-12 13:16:12",
                    "deletedAt": null
                },
                {
                    "id": 3,
                    "number": "160102",
                    "password": "202cb962ac59075b964b07152d234b70",
                    "classId": 1,
                    "createdAt": "2019-05-12 13:17:17",
                    "updatedAt": "2019-05-12 13:17:21",
                    "deletedAt": null
                },
                {
                    "id": 4,
                    "number": "160103",
                    "password": "202cb962ac59075b964b07152d234b70",
                    "classId": 1,
                    "createdAt": "2019-05-12 13:17:51",
                    "updatedAt": "2019-05-12 13:17:54",
                    "deletedAt": null
                },
                {
                    "id": 5,
                    "number": "160104",
                    "password": "202cb962ac59075b964b07152d234b70",
                    "classId": 1,
                    "createdAt": "2019-05-12 13:18:13",
                    "updatedAt": "2019-05-12 13:18:16",
                    "deletedAt": null
                }
            ]
        }
    ]
    
  • многие ко многим

    Получите информацию о курсе от студентов

    // 获取学生的选课内容
        async lession(){
          const { ctx, app } = this;
          let result = await app.model.Student.findAll({
            where:{
              id: 1,
            },
            include: [
              {model: app.model.Info},
              {model: app.model.Lession}
            ]
          });
          ctx.body = result;
        }
    

    В этом случае обратите внимание, что значением include является массив, так что данные могут быть получены из нескольких объединенных таблиц.

    Данные следующие:

    [
        {
            "id": 1,
            "number": "160101",
            "password": "202cb962ac59075b964b07152d234b70",
            "classId": 1,
            "createdAt": "2019-05-12 13:16:09",
            "updatedAt": "2019-05-12 13:16:12",
            "deletedAt": null,
            "info": {
                "sex": "男",
                "id": 1,
                "name": "许仙",
                "age": 23,
                "studentId": 1,
                "createdAt": "2019-05-12 13:25:58",
                "updatedAt": "2019-05-12 13:26:01",
                "deletedAt": null
            },
            "lessions": [
                {
                    "id": 1,
                    "name": "计算机网络",
                    "createdAt": "2019-05-12 13:12:32",
                    "updatedAt": "2019-05-12 13:12:35",
                    "deletedAt": null,
                    "lession_student": {
                        "lessionId": 1,
                        "studentId": 1,
                        "createdAt": "2019-05-12 13:20:35",
                        "updatedAt": "2019-05-12 13:20:40",
                        "deletedAt": null
                    }
                },
                {
                    "id": 2,
                    "name": "Java程序设计",
                    "createdAt": "2019-05-12 13:12:50",
                    "updatedAt": "2019-05-12 13:12:52",
                    "deletedAt": null,
                    "lession_student": {
                        "lessionId": 2,
                        "studentId": 1,
                        "createdAt": "2019-05-12 13:23:10",
                        "updatedAt": "2019-05-12 13:23:13",
                        "deletedAt": null
                    }
                },
                {
                    "id": 3,
                    "name": "软件项目管理",
                    "createdAt": "2019-05-12 13:13:07",
                    "updatedAt": "2019-05-12 13:13:10",
                    "deletedAt": null,
                    "lession_student": {
                        "lessionId": 3,
                        "studentId": 1,
                        "createdAt": "2019-05-12 13:24:21",
                        "updatedAt": "2019-05-12 13:24:24",
                        "deletedAt": null
                    }
                }
            ]
        }
    ]
    

    Получить факультативных студентов из курса:

    // 获取某个课的参课学生
        async lessionStudent(){
          const { ctx, app } = this;
          let result = await app.model.Lession.findAll({
            where:{
              name: '网络安全'
            },
            include: {
              model: app.model.Student,
              include: {
                model: app.model.Info
              }
            }
          });
          ctx.body = result;
        }
    

    Обратите внимание, что ниже включения есть еще одно включение, а второе включение относится к таблице Student.

    Данные следующие:

    [
        {
            "id": 4,
            "name": "网络安全",
            "createdAt": "2019-05-12 13:13:22",
            "updatedAt": "2019-05-12 13:13:25",
            "deletedAt": null,
            "students": [
                {
                    "id": 2,
                    "number": "160201",
                    "password": "202cb962ac59075b964b07152d234b70",
                    "classId": 2,
                    "createdAt": "2019-05-12 13:16:32",
                    "updatedAt": "2019-05-12 13:16:35",
                    "deletedAt": null,
                    "lession_student": {
                        "lessionId": 4,
                        "studentId": 2,
                        "createdAt": "2019-05-12 13:24:59",
                        "updatedAt": "2019-05-12 13:25:03",
                        "deletedAt": null
                    },
                    "info": {
                        "sex": "女",
                        "id": 2,
                        "name": "白素贞",
                        "age": 20,
                        "studentId": 2,
                        "createdAt": "2019-05-12 13:26:41",
                        "updatedAt": "2019-05-12 13:26:46",
                        "deletedAt": null
                    }
                },
                {
                    "id": 6,
                    "number": "160202",
                    "password": "202cb962ac59075b964b07152d234b70",
                    "classId": 2,
                    "createdAt": "2019-05-12 13:18:36",
                    "updatedAt": "2019-05-12 13:18:39",
                    "deletedAt": null,
                    "lession_student": {
                        "lessionId": 4,
                        "studentId": 6,
                        "createdAt": "2019-05-12 13:25:12",
                        "updatedAt": "2019-05-12 13:25:15",
                        "deletedAt": null
                    },
                    "info": {
                        "sex": "男",
                        "id": 6,
                        "name": "景松",
                        "age": 23,
                        "studentId": 6,
                        "createdAt": "2019-05-12 13:30:07",
                        "updatedAt": "2019-05-12 13:30:10",
                        "deletedAt": null
                    }
                }
            ]
        }
    ]
    

4. Резюме

На отладку, добавление настроек базы данных, написание кода и проверку документов ушло 4 часа. Позвольте мне полениться, я не хочу обобщать, внимательно прочитайте содержимое, вы можете в основном понять основное использование Sequelize в запросе к объединенной таблице.