Рубрики
Без рубрики

Как использовать Sequelize с узлом и Express

Короткое практическое руководство через некоторые из общих случаев секвенирования в узле / экспресс-проекте.

Автор оригинала: Mirko Jotic.

Этот пост будет изучать некоторые общие случаи использования Sequelize, Orm на основе обещания для узла. Письмо ориентирован на читателей, знакомых с помощью JavaScript и Back-End Development с использованием Node.js.

Как и многие другие ORMS, Sequelize позволяет сопоставлять вашу реляционную базу данных к объектам. Эти объекты имеют методы и свойства, которые позволяют избежать записи операторов SQL.

Нет ничего плохого в записи операторов SQL, но проще ошибиться, это менее читаемое, а операторы SQL немного отличаются от разных баз данных.

В двух словах ORM является формой абстракции для общих операций SQL.

Посмотрим, как мы можем использовать Sequelize для создания простых (очень, очень простых) API для хранения сообщений в блоге. Мы хотим иметь возможность создавать пользователи, сообщения блога и теги. У каждого пользователя может быть несколько сообщений в блоге, и мы можем пометить те сообщения, чтобы посетители могли быстро найти похожие посты. Каждый пост может иметь несколько тегов.

Достаточно разговоров, давайте посмотрим какой-код.

Создайте папку для нашего маленького проекта.

mkdir sequelize_example && cd sequelize_example

Тогда нам нужно будет установить наши зависимости.

npm install --save body-parser express mysql2 sequelize

Так как я буду использовать mysql, я буду устанавливать mysql2 Отказ Если вы используете другую базу данных, пожалуйста, установите соответствующий пакет ( PG PG-HStore SQLite3 Утомительно//MSSQL ). Это будет единственное, что вам нужно изменить – остальная часть этого примера является платформа Agnostic.

mkdir models
touch ./models/user.js ./models/blog.js ./models/tag.js
touch sequelize.js 
touch index.js

Это все файлы, которые нам понадобятся. Sequelize.js Будет место для загрузки нашего ORM и определяет отношения. Мы определим наши модели в своих соответствующих файлах и index.js будет наше приложение Express.

Sequelize.js.

const Sequelize = require('sequelize')
const UserModel = require('./models/user')
const BlogModel = require('./models/blog')
const TagModel = require('./models/tag')

const sequelize = new Sequelize('codementor', 'root', 'root', {
  host: 'localhost',
  dialect: 'mysql',
  pool: {
    max: 10,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
})

const User = UserModel(sequelize, Sequelize)
// BlogTag will be our way of tracking relationship between Blog and Tag models
// each Blog can have multiple tags and each Tag can have multiple blogs
const BlogTag = sequelize.define('blog_tag', {})
const Blog = BlogModel(sequelize, Sequelize)
const Tag = TagModel(sequelize, Sequelize)

Blog.belongsToMany(Tag, { through: BlogTag, unique: false })
Tag.belongsToMany(Blog, { through: BlogTag, unique: false })
Blog.belongsTo(User);

sequelize.sync({ force: true })
  .then(() => {
    console.log(`Database & tables created!`)
  })

module.exports = {
  User,
  Blog,
  Tag
}

Давайте пройдемся через то, что происходит здесь.

После того, как требуют наших моделей и зависимостей, мы создаем усиление Sequelize и определения всех деталей, необходимых для подключения к базе данных. Ваша конкретная база данных и учетные данные будут отличаться.

Далее мы создали создание наших моделей, передавая экземпляр Sequelize и сам библиотеку для необходимых моделей файлов.

После создания моделей мы определяем их отношения. Blog.belongsto (пользователь) Создаю внешний ключ в модели блога – UserID Отказ Зарубежные ключевые ключи, если вы не указываете иное, последуют следующее соглашение о именомении CAMELCASE.

Веселая часть – это отношения между Блог и Тег модели. Мы хотим иметь таблицу для всех тегов, поэтому мы можем поддерживать уникальность, но мы также хотим позволить многим сообщениям блога иметь несколько тегов.

Другие методы ассоциации не будут работать для нас, потому что мы действительно не хотим создавать внешний ключ на любую из наших моделей. То, что мы хотим, это таблица, которая будет проводить соединения между блогов и тегами. Эта таблица не должна иметь никаких полей, кроме Блогид и Тагид Отказ

Создавая пустую модель, Blogtag , что мы используем как через Свойство при настройке Прилагаются, Sequelize на самом деле добавляет два иностранных ключей в BlogtagБлогид и Тагид Отказ

Наш столик Blogtag выглядит так

+-----------+----------+------+-----+---------+-------+
| Field     | Type     | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+-------+
| createdAt | datetime | NO   |     | NULL    |       |
| updatedAt | datetime | NO   |     | NULL    |       |
| blogId    | int(11)  | NO   | PRI | NULL    |       |
| tagId     | int(11)  | NO   | PRI | NULL    |       |
+-----------+----------+------+-----+---------+-------+

Sequelize.sync () Созданете все таблицы в указанной базе данных. Если вы пройдете {Force: True} Как параметр для Синхронизация Метод, он удалит таблицы на каждом запуска и создавать новые. Само собой разумеется, это жизнеспособный вариант только для развития.

Наконец, мы хотим экспортировать наши модели, чтобы мы могли использовать их в другом месте в нашем приложении.

Переезд на наши модели.

модели/blog.js.

module.exports = (sequelize, type) => {
    return sequelize.define('blog', {
        id: {
          type: type.INTEGER,
          primaryKey: true,
          autoIncrement: true
        },
        text: type.STRING
    })
}

Модели/tag.js.

module.exports = (sequelize, type) => {
    return sequelize.define('tag', {
        id: {
          type: type.INTEGER,
          primaryKey: true,
          autoIncrement: true
        },
        name: type.STRING
    })
}

Модели/user.js.

module.exports = (sequelize, type) => {
    return sequelize.define('user', {
        id: {
          type: type.INTEGER,
          primaryKey: true,
          autoIncrement: true
        },
        name: type.STRING
    })
}

Как видите, все модели выглядят похожими. Это где мы определяем поля, типы и другую соответствующую информацию, касающуюся таблицы и ее определения. Мы экспортируем функцию, которая вернет экземпляр модели. Нам нужно пройти две вещи в наши модели файлов.

Во-первых, экземпляр Sequelize и Sequelize сам. Нам нужны первые для создания (определения) нашей модели и последнее для определения типа. Sequelize Имеет кучу типов, доступных в качестве статических свойств. Я использую Целое число и Строка , но большинство других типов также доступны.

На часть API.

Мы хотим простое приложение, которое имеет пару конечных точек: Пост /API/пользователи //Создать пользователя Получить /API/пользователи //получить всех пользователей

Пост /API/Блоги //Создать сообщение в блоге

Получить /API/Блог/: usid? //Получить все блоги | Получить блоги одного пользователя Получить /Api/блоги/: тег/тег //Получить все блоги по тегу

Давайте добавим базовый Express.js котельная. Для целей этой статьи у нас будет только один файл index.js Отказ Наша наша API будет вписываться там, но в более крупном проекте вы хотели бы организовать свой код немного лучше.

index.js.

const express = require('express')
const bodyParser = require('body-parser')

const app = express()
app.use(bodyParser.json())

// API ENDPOINTS

const port = 3000
app.listen(port, () => {
    console.log(`Running on http://localhost:${port}`)
})

Первое, что мы хотим сделать, это импортировать наши модели. index.js.

// dependencies
const { User, Blog, Tag } = require('./sequelize')

Это должно сделать это. Теперь наш Пользователи Конечные точки API действительно ничего особенного. Нам нужно только это, чтобы мы могли связать блог с пользователем.

index.js.

// create a user
app.post('/api/users', (req, res) => {
    User.create(req.body)
        .then(user => res.json(user))
})
// get all users
app.get('/api/users', (req, res) => {
    User.findAll().then(users => res.json(users))
})

Пока мы на этом, давайте посмотрим на Sequelize Методы, которые мы используем здесь. При создании пользователя мы используем Пользователь , что является ссылкой на модельный объект, который мы импортировали. создать Метод примет аргумент (объект), содержащий свойства, имеющие в наших моделях и их значениях. Например req .body будет:

{
    name: "Mirko Jotic"
}

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

Теперь приходит веселая часть. Давайте посмотрим, как мы собираемся сохранить пост блога, свяжитесь с пользователем с ним и прикрепите тег или два к нему.

index.js.

// create a blog post
app.post('/api/blogs', (req, res) => {
    const body = req.body
    // either find a tag with name or create a new one
    const tags = body.tags.map(tag => Tag.findOrCreate({ where: { name: tag.name }, defaults: { name: tag.name }})
                                         .spread((tag, created) => tag))
    User.findById(body.userId)
        .then(() => Blog.create(body))
        .then(blog => Promise.all(tags).then(storedTags => blog.addTags(storedTags)).then(() => blog))
        .then(blog => Blog.findOne({ where: {id: blog.id}, include: [User, Tag]}))
        .then(blogWithAssociations => res.json(blogWithAssociations))
        .catch(err => res.status(400).json({ err: `User with id = [${body.userId}] doesn\'t exist.`}))
})

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

Давайте посмотрим на другой случай использования. Как насчет поиска и извлечения данных.

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

index.js.

// find blogs belonging to one user or all blogs
app.get('/api/blogs/:userId?', (req, res) => {
    let query;
    if(req.params.userId) {
        query = Blog.findAll({ include: [
            { model: User, where: { id: req.params.userId } },
            { model: Tag }
        ]})
    } else {
        query = Blog.findAll({ include: [Tag, User]})
    }
    return query.then(blogs => res.json(blogs))
})

Обратите внимание, как мы можем запрашивать связанные модели в этом случае модели пользователя. С UserID Необязательный параметр, мы можем запросить с условием или без него.

Другим аналогичным применением корпуса является запрос для блогов по тегу.

index.js.

// find blogs by tag
app.get('/api/blogs/:tag/tag', (req, res) => {
    Blog.findAll({
        include: [
            { model: Tag, where: { name: req.params.tag } }
        ]
    })
    .then(blogs => res.json(blogs))
})

Вот и все, люди. Надеюсь, это было полезно. Вы можете найти весь код код для этого маленького API здесь Отказ

Отказ от ответственности: Это очень элементарный пример, сделанный для демонстрации того, как использовать Sequelize. Он оставляет многое, чтобы быть желаемым с точки зрения: аутентификация, RBAC, проверка, обработка ошибок и т. Д.