はじめに
Next.js + Prisma + PostgreSQLで開発していて、こんなエラーに遭遇したことはありませんか?
The column `contents.wordCount` does not exist in the current database.
「ローカルでは動くのに、本番環境でエラーが出る!」
今回は、この問題の原因と解決方法を、データベースを触ったことがない人でも理解できるよう、1から詳しく解説します。
目次
- そもそもデータベースのスキーマって何?
- Prismaって何をしてくれるの?
- なぜスキーマの不一致が起きるのか
- 実際に起きた問題の詳細
- 5つの解決方法
- 今後同じ問題を防ぐためのベストプラクティス
1. そもそもデータベースのスキーマって何?
Excelで考えてみよう
データベースのスキーマを理解する最も簡単な方法は、Excelに例えることです。
Excelシート = データベースのテーブル
列のヘッダー = スキーマ
例:顧客管理シート
┌────┬──────┬──────┬─────────┐
│ A │ B │ C │ D │
├────┼──────┼──────┼─────────┤
│ID │ 名前 │ 年齢 │ メール │ <- これがスキーマ!
├────┼──────┼──────┼─────────┤
│001 │ 田中 │ 25 │ xxx@... │
│002 │ 鈴木 │ 30 │ yyy@... │
└────┴──────┴──────┴─────────┘
データベースでは
-- これがスキーマの定義
CREATE TABLE customers (
id VARCHAR(255),
name VARCHAR(255),
age INTEGER,
email VARCHAR(255)
);
スキーマとは「どんな列があって、それぞれどんな種類のデータを入れるか」を決めた設計図です。
2. Prismaって何をしてくれるの?
Prismaなしの世界
データベースと直接やり取りするには、SQL(エスキューエル)という言語を使います:
// 生のSQLを書く必要がある
const result = await db.query(
'SELECT * FROM contents WHERE level = ? AND title LIKE ?',
['beginner', '%JavaScript%']
);
// エラーが起きやすい
// - SQLの文法ミス
// - テーブル名や列名のタイプミス
// - データ型の不一致
Prismaありの世界
Prismaは、JavaScriptの書き方でデータベースを操作できるようにしてくれます:
// JavaScriptらしい書き方でOK!
const result = await prisma.content.findMany({
where: {
level: 'beginner',
title: { contains: 'JavaScript' }
}
});
// メリット
// - 自動補完が効く
// - 型チェックでエラーを防げる
// - SQLを覚えなくてもOK
Prismaの仕組み
schema.prisma(設計図)
↓
Prismaが変換
↓
実際のデータベース
重要なのは、設計図と実際のデータベースを同期させる必要があるということです。
3. なぜスキーマの不一致が起きるのか
よくあるパターン1: 更新忘れ
開発の流れ:
1. ローカルで新しい機能を開発
└─ schema.prismaに列を追加
└─ prisma db push で反映 ✓
2. コードをGitHubにプッシュ
└─ schema.prismaもプッシュ ✓
3. 本番環境にデプロイ
└─ コードは更新される ✓
└─ でも、データベースは? ✗ ← ここが問題!
よくあるパターン2: 環境による差異
開発環境:
┌─────────────────────────────────┐
│ 開発者A: wordCount列あり ✓ │
│ 開発者B: wordCount列あり ✓ │
│ ステージング: wordCount列なし ✗ │
│ 本番: wordCount列なし ✗ │
└─────────────────────────────────┘
今回起きた問題
// schema.prisma(設計図)
model Content {
id String @id
title String
wordCount Int? // <- これが存在
characterCount Int? // <- これも存在
}
// コード(API)
const contents = await prisma.content.findMany({
// wordCountとcharacterCountも取得しようとする
});
しかし、本番データベースには:
-- 実際のテーブル構造
CREATE TABLE contents (
id TEXT,
title TEXT
-- wordCountとcharacterCountが存在しない!
);
4. エラーメッセージの読み解き方
Error:
Invalid `prisma.content.findMany()` invocation:
The column `contents.wordCount` does not exist in the current database.
このエラーを分解すると:
-
Invalid invocation
= 「呼び出し方が無効です」 -
prisma.content.findMany()
= 「contentテーブルから複数件取得しようとした時」 -
The column contents.wordCount does not exist
= 「contentsテーブルのwordCount列が存在しません」 -
in the current database
= 「現在接続中のデータベースに」
つまり:「設計図には書いてあるけど、実際のデータベースにその列がないよ!」という意味です。
5. 5つの解決方法
解決法1: データベースを更新する(推奨)
# 本番環境で実行
prisma db push
# または、より安全なマイグレーション
prisma migrate deploy
解決法2: ビルドスクリプトに追加
// package.json
{
"scripts": {
"build": "prisma generate && prisma db push && next build"
}
}
解決法3: 存在しない列を使わないAPI作成
// 問題のある列を除外
const contents = await prisma.content.findMany({
select: {
id: true,
title: true,
// wordCount: true, // <- 使わない
// characterCount: true, // <- 使わない
}
});
解決法4: エラーハンドリングで対処
try {
const contents = await prisma.content.findMany();
return contents;
} catch (error) {
if (error.code === 'P2022') {
// 列が存在しない場合の代替処理
const contents = await prisma.content.findMany({
select: { id: true, title: true }
});
return contents.map(c => ({
...c,
wordCount: null,
characterCount: c.title.length
}));
}
throw error;
}
解決法5: 環境変数で切り替え
const isProduction = process.env.NODE_ENV === 'production';
const contents = await prisma.content.findMany({
select: {
id: true,
title: true,
...(isProduction ? {} : {
wordCount: true,
characterCount: true
})
}
});
6. 今後同じ問題を防ぐベストプラクティス
1. マイグレーションファイルを使う
# 開発時
prisma migrate dev --name add_word_count
# 本番環境
prisma migrate deploy
2. CI/CDパイプラインに組み込む
# .github/workflows/deploy.yml
steps:
- name: Apply database migrations
run: prisma migrate deploy
- name: Deploy application
run: vercel deploy --prod
3. スキーマの同期チェックスクリプト
// scripts/check-db-sync.js
const { PrismaClient } = require('@prisma/client');
async function checkSync() {
const prisma = new PrismaClient();
try {
// テストクエリを実行
await prisma.content.findFirst();
console.log('✅ Database schema is in sync');
} catch (error) {
if (error.code === 'P2022') {
console.error('❌ Database schema mismatch detected!');
console.error('Missing columns:', error.meta?.column);
process.exit(1);
}
}
}
checkSync();
4. 環境ごとのドキュメント化
## Database Schema Status
| Environment | wordCount | characterCount | Last Updated |
|-------------|-----------|----------------|--------------|
| Local | ✅ | ✅ | 2024-01-15 |
| Staging | ✅ | ✅ | 2024-01-15 |
| Production | ❌ | ❌ | 2024-01-10 |
まとめ
「The column does not exist」エラーは、設計図(schema.prisma)と実際のデータベースがズレていることが原因です。
覚えておくべき3つのポイント
- Prismaは設計図 - 実際のデータベースとは別物
-
同期が必要 -
prisma db push
やprisma migrate
で反映 - 環境ごとに管理 - 開発・ステージング・本番で差異が生まれやすい
チェックリスト
- schema.prismaを変更したら、必ずデータベースも更新する
- デプロイ前に、本番環境のスキーマを確認する
- エラーハンドリングで、スキーマ不一致に対応する
- CI/CDにスキーマ同期を組み込む
これらを実践すれば、同じエラーで悩むことはなくなるはずです!