Серия серверных разработок Node.js, посвященная быстрому началу реального боя с нуля

Node.js
Серия серверных разработок Node.js, посвященная быстрому началу реального боя с нуля

🎇🎇🎇С Новым годом🎇🎇🎇

2020 Крыса, ты самый красивый, Крыса ты самая сильная, Ты лучшая мышка, Крыса ты самая рыжая, Ты самая красивая мышка, благоприятный год крысы

вопросы и ответы

❓: Чему вы можете научиться?
🙋: Использование секвенсора-кли и основных операций секвенсора.

❓:Зачем использовать sequenceize-cli?
🙋: Точно так же, как вы используете Git/SVN для управления изменениями исходного кода, вы можете использовать миграции для отслеживания изменений в базе данных.

❓: Почему бы не разработать модель данных, а затем продемонстрировать ее?
🙋: Эта статья о процессе разработки с использованием sequenceize-cli и sequenceize.

❓: Откуда столько кодов?
🙋: Я разместил код каждого шага, если вы следите за процессом, вы можете быстро выполнить пример. Видеть значит верить, я считаю, что так лучше учиться.

❓: Почему нет точек знаний, таких как транзакции, области действия и типы данных?
🙋: Это вводное руководство, но после его изучения становится легче понять транзакции и области действия.

❓: Почему нет исходного кода?
🙋: Лучше один раз сделать, чем один раз посмотреть.

Готов к работе

1. Инициализировать проект

 cd 工程目录 
 npm init -y

2. Установите модуль

 npm i koa koa-body koa-router mysql2 sequelize sequelize-cli -S

3. Добавьте файл server.js

 const Koa = require('koa');
 const router = require('koa-router')();
 const koaBody = require('koa-body');
 const app = new Koa();
 app.use(koaBody());

 app.use(router.routes())
    .use(router.allowedMethods('*'));

 app.listen(3000, () => {
     console.log('server is listening on 3000...')
 });

Быстрый старт

1. Создайте новый файл .sequelizerc

 const path = require('path');
 module.exports = {
   'config': path.resolve('config', 'config.json'), //数据库连接配置文件
   'models-path': path.resolve('db', 'models'),     //模型文件
   'seeders-path': path.resolve('db', 'seeders'),   //种子文件
   'migrations-path': path.resolve('db', 'migrations') //迁移文件
 }

2. Инициализация

 npx sequelize-cli init

3. Отредактируйте ./db/config.js

 "development": {
    "username": "username",
    "password": "password",
    "database": "school", //数据库名称
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00" //设置时区为'东八区'
  }

4. Создайте базу данных

 npx sequelize-cli db:create

5. СгенерироватьstudentФайлы модели и файлы миграции

 npx sequelize-cli model:generate --name student --attributes student_name:string,student_age:integer,student_sex:boolean

6. Отредактируйте ./db/migrations/xxxxx-create-student.js.

 'use strict';
 module.exports = {
   up: (queryInterface, Sequelize) => {
     return queryInterface.createTable('student', {
       id: {
         allowNull: false,
         autoIncrement: true,
         primaryKey: true,
         type: Sequelize.INTEGER
       },
       student_name: {
         type: Sequelize.STRING(10),
         allowNull:false 
       },
       student_age: {
         type: Sequelize.INTEGER,
         allowNull:false
       },
       student_sex: {
         type: Sequelize.BOOLEAN,
         allowNull:false
       }
     });
   },
   down: (queryInterface, Sequelize) => {
     return queryInterface.dropTable('student');
   }
};

Откройте xxxxx-create-student. Вы обнаружите, что первым параметром метода createTable являются студенты. Это связано с тем, что sequenceize по умолчанию преобразует имя таблицы во множественное число. Здесь я изменю его на student, а все последующие имена таблиц или имена моделей будут использовать форму единственного числа.

7. Сгенерированное имяstudentтехническая спецификация

 npx sequelize-cli db:migrate

8. Генерацияstudentначальный файл таблицы

 npx sequelize-cli seed:generate --name init-student

9. Отредактируйте файл ./db/seeders/xxxxx-init-student.js.

'use strict';

 module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('student', [{
      student_name: '孙悟空',
      student_age: 20,
      student_sex: 1
    },{
      student_name: '白骨精',
      student_age: 18,
      student_sex: 0
    },{
      student_name: '猪八戒',
      student_age: 16,
      student_sex: 1
    }])
  },

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

10.studentданные инициализации таблицы

  npx sequelize-cli db:seed:all

11. Отредактируйте .db/models/student.js

'use strict';
module.exports = (sequelize, DataTypes) => {
  const student = sequelize.define('student', {
    student_name: DataTypes.STRING,
    student_age: DataTypes.INTEGER,
    student_sex: DataTypes.BOOLEAN,
    class_id:DataTypes.INTEGER
  }, {
    timestamps: false,//不自动添加时间字段(updatedAt,createdAt)
    freezeTableName: true,// 使用模型名称的单数形式
    underscored: true //列名添加下划线
  });
  student.associate = function(models) {};
  return student;
};

12. Отредактируйте файл server.js

.....
 const Student  = require('./db/models').student;
 //添加学生信息
 router.post('/student', async ctx => {
     ctx.body = await Student.create(ctx.request.body);
 });
 //更新学生信息
 router.put('/student', async ctx => {
    const { id } = ctx.request.body;
    ctx.body = await Student.update(ctx.request.body, { where: { id } });
 });
 //获取学生列表
 router.get('/students', async ctx => {
    ctx.body = await Student.findAll();
 });
 //根据id删除学生信息
 router.delete('/student/:id', async ctx => {
    const { id } = ctx.params;
    ctx.body = await Student.destroy({ where: { id } });
});
.....

13. Запустите службу и протестируйте ее с помощью Postman.

 node server.js

подключение модели

hasMany (один ко многим)

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

  1. Создайте таблицу классов с именем _class
  2. _class данные инициализации таблицы классов
  3. Таблица учеников добавляет столбец с именем class_id.
  4. Повторно инициализировать данные таблицы учащихся
  5. Запросить всех учащихся в классе

Давайте начнем!

1. Создайте модель **_class** и файл миграции.

npx sequelize-cli model:generate --name _class --attributes class_name:string

2. Измените ./db/migrations/xxxxx-create-class.js.

 'use strict';
 module.exports = {
   up: (queryInterface, Sequelize) => {
     return queryInterface.createTable('_class', {
       id: {
         allowNull: false,
         autoIncrement: true,
          primaryKey: true,
         type: Sequelize.INTEGER
       },
       class_name: {
         type: Sequelize.STRING(10),
          allowNull:false
       }
     });
   },
   down: (queryInterface, Sequelize) => {
     return queryInterface.dropTable('_class');
   }
 };

3. Создайте таблицу **_class**

npx sequelize-cli db:migrate

4. Создайте начальный файл таблицы **_class**

 npx sequelize-cli seed:generate --name init-class

5. Отредактируйте ./db/seeders/xxxxx-init-class.js.

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('_class', [{
      class_name: '一班'
    }, {
      class_name: '二班'
    }, {
      class_name: '三班'
    }]);
  },

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

6._classданные инициализации таблицы

  npx sequelize-cli db:seed  --seed  xxxxx-init-class.js

7. Создайте файл миграции, который изменяет таблицу studnet.

npx sequelize-cli migration:generate  --name add-column-class_id-to-student.js

8. Отредактируйте ./db/migrations/xxxxx-add-column-class_id-to-student.js.

'use strict';

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.addColumn('student', 'class_id', {
      type: Sequelize.INTEGER,
      allowNull:false
    })
  },

  down: (queryInterface, Sequelize) => {
     queryInterface.removeColumn('student', 'class_id', {});
  }
};

9. Изменитьstudentповерхность

npx sequelize-cli db:migrate

10. Регенерироватьstudentначальный файл таблицы

npx sequelize-cli seed:generate --name init-student-after-add-column-class_id

11. Отредактируйте файл ./db/seeders/xxxxx-init-student-after-add-column-class_id.js.

'use strict';

 module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('student', [{
      student_name: '孙悟空',
      student_age: 20,
      student_sex: 1,
      class_id: 1
    }, {
      student_name: '白骨精',
      student_age: 18,
      student_sex: 0,
      class_id: 1
    }, {
      student_name: '猪八戒',
      student_age: 16,
      student_sex: 1,
      class_id: 2
    }, {
      student_name: '唐僧',
      student_age: 22,
      student_sex: 1,
      class_id: 1
    }, {
      student_name: '沙和尚',
      student_age: 25,
      student_sex: 1,
      class_id: 1
    }, {
      student_name: '红孩儿',
      student_age: 13,
      student_sex: 1,
      class_id: 2
    }, {
      student_name: '黑熊怪',
      student_age: 26,
      student_sex: 1,
      class_id: 2
    }, {
      student_name: '太白金星',
      student_age: 66,
      student_sex: 1,
      class_id: 3
    }, {
      student_name: '嫦娥',
      student_age: 18,
      student_sex: 0,
      class_id: 3
    }])
  },

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

12. ОтменаstudentДанные уже в таблице

npx sequelize-cli db:seed:undo --seed xxxxx-init-student.js

13.stuentтаблица повторно инициализирует данные

npx sequelize-cli db:seed --seed  xxxxx-init-student-after-add-column-class_id.js

14. Отредактируйте файл ./db/models/_class.js.

'use strict';
module.exports = (sequelize, DataTypes) => {
  const _class = sequelize.define('_class', {
    class_name: DataTypes.STRING
  }, {
    timestamps: false,
    freezeTableName: true,
    underscored: true
  });
  _class.associate = function (models) {
    _class.hasMany(models.student);
  };
  return _class;
};

15. Отредактируйте server.js

...
const Class = require('./db/models')._class;

//获取班级信息以及班级里的所有学生
router.get('/classes', async ctx => {
    //获取所有班级以及学生信息
     ctx.body = await Class.findAll({ include: [Student] });
});
...

принадлежит (один к одному)

Ученик может принадлежать только к одному классу, поэтому отношения между учеником и классомодин на один.

1. Измените файл ./db/models/student.js.

 ...
  student.associate = function(models) {
    student.belongsTo(models._class); //一对一
  };
 ...

2. Измените интерфейс получения списка учеников в server.js.

...
//获取学生列表
router.get('/students', async ctx => {
    ctx.body = await Student.findAll({ include: [Class] });
});
...

belongsTo VS hasOne

student.belongsTo(models._class), где студент называетсяисходная модель, _class называетсяцелевая модель.

Таблица Student содержит внешний ключ class_id таблицы _class, что означает, что внешний ключ находится висходная модельвыше, поэтому мы используемbelongsToдля создания ассоциации.

hasOneиbelongsToиспользуются для созданияодин на одинАссоциативный, правильный способ их использования — посмотреть, в какой модели находится внешний ключ.

  • Принадлежит к внешнему ключу ассоциации в исходной модели
  • Внешний ключ ассоциации hasOne для целевой модели

принадлежитToMany (многие ко многим)

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

  1. создать имя

Давайте начнем!

1. СгенерироватьteacherФайлы модели и миграции

npx sequelize-cli model:generate --name teacher --attributes teacher_name:string

2. Измените ./db/migrations/xxxxx-teacher-class.js.

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('teacher', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      teacher_name: {
        type: Sequelize.STRING(10),
        allowNull: false
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('teacher');
  }
};

3. Сгенерироватьteacherповерхность

npx sequelize-cli db:migrate

4. Сгенерироватьteacherначальный файл таблицы

 npx sequelize-cli seed:generate --name init-teacher

5. Отредактируйте ./db/seeders/xxxxx-init-teacher.js.

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('teacher', [{
      teacher_name: '李老师'
    }, {
      teacher_name: '张老师'
    }]);
  },

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

6.teacherданные инициализации таблицы

  npx sequelize-cli db:seed  --seed  xxxxx-init-teacher.js

7. Генерацияteacher_classФайлы модели и миграции

npx sequelize-cli model:generate --name teacher_class --attributes teacher_id:integer,class_id:integer

8. Отредактируйте ./db/migrations/xxxxx-create-teacher-class.js.

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('teacher_class', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      teacher_id: {
        type: Sequelize.INTEGER,
        allowNull: false,
      },
      class_id: {
        type: Sequelize.INTEGER,
        allowNull: false,
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('teacher_class');
  }
};

9. Генерацияteacher_classповерхность

npx sequelize-cli db:migrate

10. Сгенерироватьteacher_classначальный файл таблицы

 npx sequelize-cli seed:generate --name init-teacher_class

11. Отредактируйте ./db/seeders/xxxxx-init-teacher_class.js

'use strict';

/* 李老师带的班级为一班和二班。张老师带的班级为三班 */
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('teacher_class', [{
      class_id: 1,
      teacher_id: 1
    }, {
      class_id: 2,
      teacher_id: 1
    }, {
      class_id: 3,
      teacher_id: 2
    }]);
  },

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

12.teacher_classданные инициализации таблицы

  npx sequelize-cli db:seed  --seed  xxxxx-init-teacher_class.js

13. Отредактируйте ./db/models/teacher.js

'use strict';
module.exports = (sequelize, DataTypes) => {
  const teacher = sequelize.define('teacher', {
    teacher_name: DataTypes.STRING
  }, {
    timestamps: false,
    freezeTableName: true,
    underscored: true
  });
  teacher.associate = function (models) {
    teacher.belongsToMany(models._class, {
      through: models.teacher_class,
      foreignKey: 'teacher_id',
    });
  };
  return teacher;
};

14. Отредактируйте ./db/models/_class.js

'use strict';
module.exports = (sequelize, DataTypes) => {
  const _class = sequelize.define('_class', {
    class_name: DataTypes.STRING
  }, {
    timestamps: false,
    freezeTableName: true,
    underscored: true
  });
  _class.associate = function (models) {
    _class.hasMany(models.student);
    _class.belongsToMany(models.teacher, {
      through: models.teacher_class,
      foreignKey: 'class_id',
    });
  };
  return _class;
};

15. Отредактируйте server.js

const Teacher = require('./db/models').teacher;

//获取老师信息以及老师所带的班级
router.get('/teachers', async ctx => {
    //获取所有班级以及学生信息
     ctx.body = await Teacher.findAll({ include: [Class] });
})

Запрос

Базовый запрос

1. Вернуть указанный столбец

 Student.findAll({
    attributes: ['id', 'student_name']
 });
 // select id,student_name from student

2. Запрос с одним условием

 Student.findAll({
    where: {
      id: 1
    }
 })
 // select * from student where id = 1

3. И

 //返回id为1,姓名是`孙悟空`的学生信息
 Student.findAll({
        where: {
            id: 4,
            student_name:'孙悟空'
        }
    })
 // select * from student where id = 1 and student_name = '孙悟空'

4. ИЛИ

 //返回年龄等于12或者22的学生信息
 Student.findAll({
     where: {
            student_age: {
                [Op.or]: [12, 22]
            }
        }
 })
 // select * from student where studnet_age = 12 or studnet_age = 22

5. Условный запрос - >,>=,

 // 返回年龄大于等于20的学生
 Student.findAll({
     where: {
            student_age: {
                [Op.gte]: 20
            }
        }
 })
 // select * from student where studnet_age >= 20
 [Op.gt]: 6      //大于6
 [Op.gte]: 6     //大于等于6
 [Op.lt]: 10     //小于10
 [Op.lte]: 10    //小于等于10
 [Op.ne]: 20     //不等于20
 [Op.eq]: 3      //等于3

6. В

 // 返回年龄是16和18的学生信息
 Student.findAll({
     where: {
        student_age: {
            [Op.in]: [16,18]
        }
    }
 })
 // select * from student where studnet_age in (16,18)

7. НРАВИТСЯ

  // 返回名称包含'孙'的学生信息
 Student.findAll({
     where: {
        student_name: {
           [Op.like]: '%孙%',
        }
    }
 })
 // select * from student where studnet_name like '%孙%'

Агрегатная функция

1. Получите средний возраст учащихся

 Student.findAll({
    attributes: [[sequelize.fn('AVG', sequelize.col('student_age')), 'avg']]
 })

2. Получите общее количество студентов

  Student.findAll({
     attributes: [[sequelize.fn('COUNT', sequelize.col('id')), 'count']]
 })

вложенный запрос

1. Соберите всех учеников в классе и отсортируйте их в порядке убывания по возрасту.

 Class.findAll({
    include: [{model: Student}],
    where:{id:1},
    order:[[Student,'student_age', 'DESC']]
    });

Ссылаться на

продолжить китайскую документацию