前提と注意事項
- Supabase アカウントを作成済みであること
- Supabase のプロジェクトを作成済みであること
- この記事では、Next.js でのプロジェクトを想定し、Next.js でユーザーがアップした CSV データを Supabase の Database Functions に送信します。
- Next.js のバージョンは 14.0.0 で API route を使用しています。
なお、Next.js で CSV データを受け取る部分については以下の記事の内容を前提にしています。
上記の記事の内容と合わせて、Supabase のテーブルとして顧客情報を保存するための以下のようなcustomers
テーブルがすでに存在しているものとします。
CREATE TABLE public.customers (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
name text,
namekana text,
age decimal,
birthday date,
company text,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
CONSTRAINT customers_pkey PRIMARY KEY (id)
);
この記事のゴール
Supabase で Database Functions を用意して、それを Next.js で呼び出して CSV データを渡すことでそのデータを Supabase のテーブルにインポートすることがこの記事のゴールになります。
具体的には、Next.js で CSV ファイルをアップロードして以下のようなデータを Supabase Database Functions に送信し、それを Supabase のテーブルにインポートすることを目指します。
[
{
"name": "John",
"namekana": "ジョン",
"age": 20,
"birthday": "2000-01-01",
"company": "examplecompany1"
},
{
"name": "Jane",
"namekana": "ジェーン",
"age": 30,
"birthday": "1990-01-01",
"company": "examplecompany2"
},
{
"name": "Bob",
"namekana": "ボブ",
"age": 40,
"birthday": "1980-01-01",
"company": "examplecompany3"
}
...
]
CSV データを受け取ってインポートする Database Functions を作成する
以下の Supabase の Database Functions を作成します。
DROP FUNCTION IF EXISTS import_customers;
CREATE OR REPLACE FUNCTION import_customers(data jsonb)
RETURNS void AS $$
DECLARE
record jsonb;
BEGIN
FOR record IN SELECT * FROM jsonb_array_elements(data)
LOOP
INSERT INTO public.customers (
name,
namekana,
age,
birthday,
company,
created_at,
updated_at
)
VALUES (
(record->>'name')::text,
(record->>'namekana')::text,
(record->>'age')::DECIMAL,
(record->>'company')::text,
now(),
now()
);
END LOOP;
END;
$$ LANGUAGE plpgsql;
上記は、Next.js などフロント側から CSV のデータをjsonb
データとして受け取って、それらを愚直にLOOP
で1つづつテーブルにインサートする関数です。
LOOP
を使わずに 1 つのINSERT
文でまとめてインサートする方法もありますが、今回は大量のデータではなくかつ使用頻度も少ないため上記のようにLOOP
を使ったものにしています。
あとはこのDatabase FunctionsをNext.jsで呼び出します。
なお、上記は受け取ったデータの検証などは行なっていないため、値がnull
である場合は何かしらのデフォルト値で置き換えたいなどある場合は、NULLIF
などを使うのが良いと思います。
Supabase の Database Functions を呼び出す API route を作成する
Next.js で Supabase のクライアントは準備できているとし、以下のようにして Supabase の Database Functions を使うための API ルートを作成します。
import { NextResponse } from 'next/server';
// Supabase Client
import { getSupabaseClient } from '@/utils/supabaseClient';
// import customer records
export async function POST(request: Request) {
// アップロードしたCSVデータを取得
const reqData = await request.json();
let _error: any = null;
// Supabaseクライアントを準備
const supabase = getSupabaseClient();
// rpcでDatabase Functionsを呼び出す
const { error: _error } = await supabase.rpc('import_customers', {
data: reqData, // csvデータを渡す
});
if (_error) {
return NextResponse.json({ message: _error.message }, { status: 500 });
}
return NextResponse.json({ message: 'Success' }, { status: 200 });
}
上記で@/utils/supabaseClient
からgetSupabaseClient
を呼び出して使っていますが、この部分については Supabase の公式ドキュメントのものを参考にしています。
CSV データを API ルートに送信する関数を用意する
後は以下のようにして、CSV データを API ルートに POST するための関数を用意しておきます。
'use server';
import { headers } from 'next/headers';
// POST API
export async function postApi(newData: any) {
const _apiUrl = '/api/customers';
try {
const res = await fetch(_apiUrl, {
method: 'POST',
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
cookie: headers().get('cookie') as string,
},
body: JSON.stringify(newData),
});
if (res.status !== 200) {
const error = await res.text();
return { data: null, error: error };
}
const data = await res.json();
return { data: data.data, error: null };
} catch (e) {
console.error(e);
return { data: null, error: true };
}
}
あとはインポート実行ボタンを押した場合などに以下のようにpostApi
に CSV データを渡して実行すれば Supabase に CSV データをインポートできるはずです。
import { postApi } from '@/utils/api';
// インポート実行ボタンを押した時の処理
const handleOnImport = async () => {
// 省略
// uploadedListにはアップロードしたCSVデータが入っているとする。
const response = await postApi(uploadedList);
// 省略
};
まとめ
Next.js で受け取った CSV データを Supabase のテーブルにインポートするために、Supabase の Database Functions を作成し、それを Next.js から呼び出す方法を解説しました。もし大量のデータをインポートする場合は、今回のように Database Functions を使う方法ではなく、別のサーバーでpgloader
を使うなどの方法もあります。