LoginSignup
4
3

prisma を勉強したときのまとめ(個人備忘録)

Last updated at Posted at 2023-07-03

参考文献

Node.js(Express.js)環境でPrisma ORMを使いこなすための基礎 一部old
node.js / Prisma ORM / mysql を試す例
Prisma Migrationの動作を確認してみた
prismaのschemaファイルの書き方(MySQL用)
マイグレーション|Prismaチュートリアル
[Prisma] チートシート - Qiita
prisma 入門 2022


概要

Prismaとは、Node.js/TypeScript環境で利用できるオープンソースのORMである。

ORM(Object Relational Mapping)とは、オブジェクトとデータベースをマッピングするための技術である。

つまりPrismaとは、データベースを効率的に管理し、簡単に操作を行うためのツールである。

Prismaでは、どのデータベースを利用しているか意識することなく、共通のオブジェクトメソッドを利用し、データベースを操作することができる。

Prismaはアプリケーションを構築する上で必須のツールではなりませんが、データベースの操作に関わるアプリケーション開発のスピードを飛躍的に向上させることができます。

機能構成

  • Prisma Client
    データベースの操作に利用する機能。
npx prisma generate

schemaを変更した際にズレが生じ、npm run dev した際に毎回エラーが出るのでpackage.jsonに記述しておくと良い。

 "scripts": {
    "dev": "ts-node ./script.ts",
    "prisma": "prisma generate"
  },
  • Prisma Migrate
    Prismaの設定ファイル(schema.prisma)にデータモデルを記述しマイグレーションを行うことでデータベースにテーブルを作成することができます。
    schema を作成した後に実行する。
  • Prisma Studio
npx prisma studio

テーブルをブラウザ上で閲覧するためのUIも提供しておりブラウザ上からテーブル内のデータを編集することができます。モデル間のリレーションの関係もブラウザ上から把握することができます。


環境構築

TypeScript, Prisma, Expressのインストール

npde -v
npm -v

mkdir nodejs-prisma
cd nodejs-prisma
npm init -y

npm install typescript ts-node @types/node --save-dev
npx tsc --init

npm install express
npm install @types/express --save-dev # TypesScript用にExpress.jsの型定義をインストール

npm install prisma --save-dev
npx prisma # Prismaで利用できるコマンドのオプションを確認
npx prisma init # プロジェクトフォルダにprismaフォルダと.envファイルが作成される
# npx prisma init --datasource-provider sqlite # DBの設定変更(デフォルトはpostgresql)
# npx prisma init --datasource-provider mysql # DBの設定変更(デフォルトはpostgresql)
  • prismaフォルダ内:設定ファイルであるschema.prismaファイル
  • .envファイル:データベースに接続するために必要となる環境変数を設定する

DBの設定

schema.prisma ファイルと .env ファイル内を変更
DB作成権限がないとエラーになる
mysql://ユーザー名:パスワード@localhost:3306/DB名

DATABASE_URL="mysql://root:prismatest@localhost:33063/testd02"
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

ブラウザで localhost:33063 にアクセスできませんでした。

potsテーブルを作成するためにデータモデルの定義(Data model Definition)を記述する

model pot {
  id      Int      @id @default(autoincrement())
  name    String
  score   Int?    @unique
  email   String  @@map('e_mail')

  @@map('pots')
}

@id:主キー
@default():デフォルト値セット
autoincrement():自動採番
?:null許容
@unique:カラムで一意の値
@@unique([column1, column2]):複合キー
@@map('e-mail'):独自の名前をマッピングできる

フィールド

link
refarence

types types_schema type attribute
varchar String @db.VarChar(X)
char String @db.Char(X)
TINYINT(1) Boolean @db.TinyInt(1)
BIT(1) Boolean @db.Bit(1)
datetime DateTime @db.DateTime()
date DateTime @db.Date()
time DateTime @db.Time()
timestamp DateTime @db.Timestamp()

マイグレーションの実行

shema.prisma に記述したモデルを元にデータベースにテーブルを作成すること
マイグレーションに任意の名前をつける必要がある

npx prisma migrate dev --name my_migrate_init

migration フォルダとその中に migration.sql ファイルが生成される。

Prisma Studio でテーブルへのアクセス

npx prisma studio

ブラウザで localhost:5555 にアクセスできませんでした。
ブラウザで localhost:33036 にアクセスしたら文字化け出ました。

マイグレーションのリセット

テーブルを一度削除し再生成します。

npx prisma migrate reset

マイグレーションのpushとpull

  • npx prisma db push
    schema.prisma ファイルのモデルを変更した際に、migration ファイルを生成せずにテーブルを変更する。
  • npx prisma db pull
    現在のDBの状態を schema.prisma ファイルに反映させる。

マイグレーションによるSeeding

Seeding ファイルを利用すると、マイグレーションの実行時にテーブルにデータを挿入できる。
prisma フォルダに seed.ts ファイルを作成しデータをテーブルに追加する処理を記述。
なんかよくわからん。諦🍈 → here

Express.js の設定

TSとJSが混在しています。

### Prisma を経由して users テーブルを操作する関数。

  • findMany:全データを取得する
const prisma = new PrismaClient();

app.get('/users', async (req: Request, res: Response) => {
  const users = await prisma.users.findMany();
  return res.json(users);
});
  • create:データの登録
app.post('/users', async (req: Request, res: Response) => {
  const { name, email } = req.body;
  try {
    const user = await prisma.user.create({
      data: {
        name,
        email,
      },
    });
    return res.json(user);
  } catch (e) {
    if (e instanceof Prisma.PrismaClientKnownRequestError) {
      if (e.code === 'P2002') {
        console.log(
          'There is a unique constraint violation, a new user cannot be created with this email'
        );
      }
    }
    return res.status(400).json(e);
  }
});
  • update:データの更新
app.put('/users/:id', async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  const { name } = req.body;
  try {
    const user = await prisma.users.update({
      where: {
        id,
      },
      data: {
        name,
      },
    });
    return res.json(user);
  } catch (e) {
    return res.status(400).json(e);
  }
});
  • delete:データの削除
app.delete('/users/:id', async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  try {
    const user = await prisma.users.delete({
      where: {
        id,
      },
    });
    return res.json(user);
  } catch (e) {
    return res.status(400).json(e);
  }
});
  • findUnique:特定フィールドの取得
app.get('/users/:id', async (req: Request, res: Response) => {
  const id = Number(req.params.id);
  try {
    const user = await prisma.users.findUnique({
      where: {
        id,
      },
    });
    return res.json(user);
  } catch (e) {
    return res.status(400).json(e);
    console.log('IDが存在しません。')
  }
});

### その他のメソッド

  • findFirst:最後に追加されたフィールドの取得
const user = await prisma.users.findFirst({
  where: { name: 'Alice' },
})
  • upsert:指定したIDが存在する場合update、存在しない場合createを実行
const user = await prisma.users.upsert({
  where: { id: 1 },
  create: {
    email: 'alice@prisma.io',
    name: 'Alice',
  },
  update: {
    email: 'alice@prisma.io',
    name: 'AliceB',
  },
})
  • createMany:一度に複数のフィールドの挿入
const users = await prisma.users.createMany({
  data: [
    { name: 'Sonali', email: 'sonali@prisma.io' },
    { name: 'Alex', email: 'alex@prisma.io' },
  ],
})
  • updateMany:一度に複数のフィールドを更新
  • deleteMany:一度に複数のフィールドを削除

メソッド未確認。
確認済:findMany
未確認:create, and so on

リレーションの設定

link
refarence

schema.prisma ファイルに追加記述

  • 1対Nの場合
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  Posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}

もしくはマッチングキーを利用

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  Posts Post[]  @relation("author") 
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation("author", fields: [authorId], references: [id])
  authorId Int
}

下記の sql と同等

-- テーブルの外部キー制約
-- 1対NのNの方のテーブルにキー制約をかける。
ALTER TABLE `Post`
  ADD CONSTRAINT `author` FOREIGN KEY (`authorId`) REFERENCES `User` (`id`);

複数カラムが同じテーブルにつながっている場合

リレーション名を設定して一意にする。

model videos {
  V_id         Int    @id @default(autoincrement())
  V_title      String @db.VarChar(255)

  V_VP_a video_pairs[] @relation("a")
  V_VP_b video_pairs[] @relation("b")
}

model video_pairs {
  VP_id         Int @id @default(autoincrement())
  VP_a_video_id Int
  VP_b_video_id Int

  VP_V_a videos @relation(fields:[VP_a_video_id], references:[V_id], name: "a")
  VP_V_b videos @relation(fields:[VP_b_video_id], references:[V_id], name: "b")
}

VIEW or JOIN

Migrate を使用してスキーマ内のビューをデータベースに適用することはまだできません
手動でなんかいろいろせにゃならんでめんどくさいみたいです。

prisma.jsで覚えたメモ
How to include views in your Prisma schema
PrismaのJOINの挙動を観察
How to create a prisma model from a SQL view - Stack Overflow
データベース ビューのサポートを追加 GitHub
PrismaからRDBのViewを参照する

DBに別の方法でViewを作成し schema を記述すると参照できる。

import { PrismaClient } from '@prisma/client';

(async () => {
  const prisma = new PrismaClient({
    log: ['query'],
  });
  const params = await prisma.user.findMany({
    select: {
      id: true,
      name: true,
      UserConfig: {
        select: {
          category: true
        }
      }
    },
    where: {
      UserConfig: {
        category: {
          in: ['01', '02']
        }
      }
    }
  });
  console.log(params);
})();

prisma/seed.ts feat. Relations

PrismaでSeedでデータを投入する
prismaのseedを複数ファイルに分割する
Seeding with relations?
Relations (Reference)
Seeding your database

  1. seed ファイルを用意
    複数ファイルに分割したい場合、 seed ディレクトリを作成し、中にファイルを用意
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

async function main() {
const alice = await prisma.users.upsert({
   where: { U_id: 1 },
   update: {},
   create: {
      U_name: 'alice@prisma.io',
      U_age: 21,
      U_gender: 0,
   },
});

console.log({ alice });
}

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

または

import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient()

// モデル投入用のデータ定義
const userData: Prisma.UserCreateInput[] = [
  {
    name: 'hoge1',
    email: 'hoge1@example.com',
  },
  {
    name: 'hoge2',
    email: 'hoge2@example.com',
  },
  {
    name: 'hoge3',
    email: 'hoge3@example.com',
  },
]

const transfer = async () => {
  const users = [];
  for (const u of userData) {
    const user = prisma.user.create({
      data: u,
    })
    users.push(user);
  }
  return await prisma.$transaction(users);
}

// 定義されたデータを実際のモデルへ登録する処理
const main = async () => {
  console.log(`Start seeding ...`)

  await transfer();

  console.log(`Seeding finished.`)
}

// 処理開始
main()
  .catch((e) => {
    console.error(e)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })
  1. package.jsonにprismaのseedの設定を加えます。
"prisma": {
  "seed": "ts-node prisma/seed.ts"
}

複数ファイルに分割した場合以下のようにする。

"prisma": {
  "seed": "ts-node ./prisma/seed/start.ts"
}
  1. 実行
npx prisma db seed

API 作成時の SELECT 文

Prismaでリレーション先のデータもSELECTしたい場合のパラメータ覚書
Prismaで、リレーション先のデータに対するWHEREクエリを作る
Select fields (Concepts)

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3