【NodeJS】PrismaやTypeScript、MySQLを使ってデータを操作する

Node.js

1. 概要

今回はPrismaを使ってMySQLにデータを登録しながら抽出まで行う内容になります。

前回はSQLiteを使いました。

対象としては開発を1年程やってて自分で最初から開発してみたい方になります。そのため細かい用語などの説明はしません。

2. Prismaとは

  • ORM for Node.js & Typescript

Node.jsとTypeScriptで利用できるORM(Object Relational Mapping)のようです。

Prisma | Next-generation ORM for Node.js & TypeScript

3. nodeのインストール

こちらを参考

ここからは公式サイトの手順に従い、やってみます。

4. プロジェクトを作成

mkdir hello-prisma-mysql
cd hello-prisma-mysql

5. 必要なライブラリをインストール

npm init -y
npm install prisma typescript ts-node @types/node --save-dev

6. セットアップ

npx tsc --init
npx prisma init

7. Databaseへ接続設定

touch .env
DATABASE_URL="mysql://user:password@localhost:3306/mydb"

※「prisma/schema.prisma」を修正

  • 変更前
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
  • 変更後
    • 「postgresql」⇒「mysql」
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

8. スキーマを定義

※「prisma/schema.prisma」に追加

model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  title     String   @db.VarChar(255)
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

model Profile {
  id     Int     @id @default(autoincrement())
  bio    String?
  user   User    @relation(fields: [userId], references: [id])
  userId Int     @unique
}

model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  posts   Post[]
  profile Profile?
}
  • model「Post」「Profile」「User」を追加

9. MySQLを起動

こちらを参考

docker-compose up -d

※「user」にパーミッションを付与

docker-compose exec mysql-server bash
# コンテナ内でrootでmysqlに接続
$ mysql -uroot -proot mysql

# mysql内でALL権限付与
mysql> GRANT ALL ON *.* TO 'user';

# 反映
mysql> FLUSH PRIVILEGES;

10. スキーマを作成

npx prisma migrate dev --name init
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "mydb" at "localhost:3306"

MySQL database mydb created at localhost:3306

Applying migration `20230711080111_init`

The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20230711080111_init/
    └─ migration.sql

Your database is now in sync with your schema.

Running generate... (Use --skip-generate to skip the generators)

added 2 packages, and audited 24 packages in 7s

found 0 vulnerabilities

✔ Generated Prisma Client (4.16.2 | library) to ./node_modules/@prisma/client in 84ms

11. スキーマを確認

docker-compose exec mysql-server mysql -hlocalhost -uuser -p mydb

OR

mysql -hlocalhost -uuser -p mydb --protocol=tcp
mysql> SHOW TABLES;
+--------------------+
| Tables_in_mydb     |
+--------------------+
| Post               |
| Profile            |
| User               |
| _prisma_migrations |
+--------------------+
4 rows in set (0.00 sec)

12. Prismaクライアントをインストール

npm install @prisma/client

13. データを登録

※src/create-data.ts

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  await prisma.user.create({
    data: {
      name: 'Alice',
      email: 'alice@prisma.io',
      posts: {
        create: { title: 'Hello World' },
      },
      profile: {
        create: { bio: 'I like turtles' },
      },
    },
  })

  const allUsers = await prisma.user.findMany({
    include: {
      posts: true,
      profile: true,
    },
  })
  console.dir(allUsers, { depth: null })
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })

実行

npx ts-node src/create-data.ts
[
  {
    id: 1,
    email: 'alice@prisma.io',
    name: 'Alice',
    posts: [
      {
        id: 1,
        createdAt: 2023-07-11T11:11:25.280Z,
        updatedAt: 2023-07-11T11:11:25.280Z,
        title: 'Hello World',
        content: null,
        published: false,
        authorId: 1
      }
    ],
    profile: { id: 1, bio: 'I like turtles', userId: 1 }
  }
]

確認

mysql> SELECT * FROM User;
+----+-----------------+-------+
| id | email           | name  |
+----+-----------------+-------+
|  1 | alice@prisma.io | Alice |
+----+-----------------+-------+
1 row in set (0.01 sec)

mysql> SELECT * FROM Post;
+----+-------------------------+-------------------------+-------------+---------+-----------+----------+
| id | createdAt               | updatedAt               | title       | content | published | authorId |
+----+-------------------------+-------------------------+-------------+---------+-----------+----------+
|  1 | 2023-07-11 11:11:25.280 | 2023-07-11 11:11:25.280 | Hello World | NULL    |         0 |        1 |
+----+-------------------------+-------------------------+-------------+---------+-----------+----------+
1 row in set (0.00 sec)

mysql> SELECT * FROM Profile;
+----+----------------+--------+
| id | bio            | userId |
+----+----------------+--------+
|  1 | I like turtles |      1 |
+----+----------------+--------+
1 row in set (0.00 sec)

14. データを取得

※src/select-data.ts

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  const allUsers = await prisma.user.findMany()
  console.log(allUsers)
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })

実行

npx ts-node src/select-data.ts
[ { id: 1, email: 'alice@prisma.io', name: 'Alice' } ]

15. データを更新

※src/update-data.ts

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  const post = await prisma.post.update({
    where: { id: 1 },
    data: { published: true },
  })
  console.log(post)
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })

実行

npx ts-node src/update-data.ts
{
  id: 1,
  createdAt: 2023-07-11T11:11:25.280Z,
  updatedAt: 2023-07-11T11:15:16.263Z,
  title: 'Hello World',
  content: null,
  published: true,
  authorId: 1
}

確認

mysql> SELECT * FROM Post;
+----+-------------------------+-------------------------+-------------+---------+-----------+----------+
| id | createdAt               | updatedAt               | title       | content | published | authorId |
+----+-------------------------+-------------------------+-------------+---------+-----------+----------+
|  1 | 2023-07-11 11:11:25.280 | 2023-07-11 11:15:16.263 | Hello World | NULL    |         1 |        1 |
+----+-------------------------+-------------------------+-------------+---------+-----------+----------+
1 row in set (0.00 sec)
  • 「published」が「0」から「1」へ更新

16. ディレクトリの構造

.
├── package-lock.json
├── package.json
├── prisma
│   ├── migrations
│   │   ├── 20230711080111_init
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   └── schema.prisma
├── src
│   ├── create-data.ts
│   ├── select-data.ts
│   └── update-data.ts
└── tsconfig.json

4 directories, 9 files

17. 備考

今回は公式サイトの手順に従い、PrismaとMySQLを使ってデータを操作するシンプルな内容でした。

18. 参考

投稿者プロフィール

Sondon
開発好きなシステムエンジニアです。
卓球にハマってます。

関連記事

  1. Node.js

    【NodeJS】Geminiを使った画像生成(Nano Banana)…

  2. Node.jsバージョン管理ツールについて調べてみる

  3. Node.js

    【NodeJS】PrismaやTypeScriptを使ってデータを操作…

  4. Node.js

    【NodeJS】Gemini APIを使ってみる

  5. Node.js

    【NodeJS】自作MCPサーバー with Gemini CLI

  6. Node.js

    【NodeJS】TypeScriptでCSVを読み込んで処理する

最近の記事

制作実績一覧

  1. Checkeys