ハコヅミを作る #7:Notion から実際のギアとコンテナを取り込む
前回(#6)までで、ギアとコンテナの機能がそろいました。 ここからプランやチェックリストを作っていく前に、実際のデータを入れることにしました。
#1で書いたとおり、今の持ち物はNotionのデータベースで管理しています。これをハコヅミに取り込めば、このあとの機能を、本物のギアとコンテナで確かめられます。
方針:画面は作らず、スクリプトで一度に入れる
取り込みは、基本的に一度きりです。画面を作るほどではないので、次の形にしました。
- NotionのデータベースをCSVで書き出す
- CSVを読んで、取り込み用のSQLを出すスクリプトを動かす
- そのSQLを、開発 → 本番の順にD1で実行する
CSVは個人の持ち物のデータなので、リポジトリには入れず、Gitの対象外のフォルダに置いて使います。
項目の対応を決める
Notionのデータベースと、ハコヅミの項目は、ほぼ対応しています。違いがあるところだけ、Issueの段階で決めました。
| Notion | ハコヅミ |
|---|---|
| 製品名(空なら「キャンプ道具」の名前) | 製品名 |
| メーカー | メーカー |
| 分類 | カテゴリ |
| 廃棄済 | 状態(廃棄済なら「廃棄済」、それ以外は「所有」) |
| 収納 | コンテナ(値ごとに1つ作る) |
| スタイル・人数 | 取り込まない(プランを作るときの参考にする) |
| チェック・今回不要 | 取り込まない(キャンプ1回ごとの情報のため) |
迷ったのは次の2点です。
- 製品名が空の行:Notionでは「キャンプ道具」(テント、ランタンなど)がタイトルで、製品名は空のこともあります。ハコヅミは#3で「ギアは製品名で表す」と決めたので、製品名が空なら「キャンプ道具」の名前を製品名にしました
- 収納の「テント」「焚火台」:カーゴボックスではなく、テントや焚火台の収納袋です。それでも「袋ごと積めば中身もそろう」という意味では同じなので、コンテナとして作ることにしました
全件を消してから入れる
開発環境にも本番環境にも、受入確認のときに登録したテストのギアやコンテナが残っていました。 取り込んだあとは、Notionのデータだけにしたかったので、SQLの先頭で全件を消すことにしました。
DELETE FROM gears;
DELETE FROM containers;
INSERT INTO containers (...) VALUES (...);
INSERT INTO gears (...) VALUES (...);
...
外部キーがあるので、消すのはギア → コンテナの順、入れるのはコンテナ → ギアの順です。
こうしておくと、何度実行しても結果は同じになります。途中で失敗しても、もう一度流せば済みます。「一度きり」のつもりでも、やり直しが効くのは安心です。
CSVの読み取りは自前で
技術スタックの方針で「依存パッケージは増やさない」としているので、CSVを読む処理も自前で書きました。 Notionが書き出すCSVには、先頭のBOM、ダブルクォートで囲んだ値、値の中のカンマ(「日帰り, 宿泊」など)があります。この範囲に対応する小さな関数で足りました。
作ったSQLが本当にD1で動くかは、Notionと同じ形の作り物のCSVで試しました。手元のD1に2回流して、1回目でテストのデータ(ギア647件)が消えて4件になり、2回目も同じ結果になることを確かめています。
SQLは、ダッシュボードのコンソールで実行する
ここで、#2で決めた「手元から開発・本番のD1に書き込まない」ルールが関係してきます。
手元の wrangler d1 execute --remote は使えないので、CloudflareのダッシュボードのD1のコンソールにSQLを貼って、自分で実行することにしました。
つまずき1:ターミナル用のコマンドを貼ってしまった
最初に、SQLのファイルを開くためのターミナル用のコマンド(open -a TextEdit ...)を、そのままコンソールに貼って実行してしまいました。Claude Codeの案内が、どこで実行するコマンドなのか分かりにくい書き方だったためです。
当然、SQLとしては文法エラーです。データベースは何も変わっていませんでした。
SQLの中身は、ターミナルで pbcopy を使ってクリップボードに入れるのが一番簡単でした。
pbcopy < scripts/notion-import/data/import.sql
つまずき2:コメント行があると実行できない
次に、SQLを貼って実行すると、今度はこう返されました。
The request is malformed: Requests without any query are not supported.
原因は、SQLの先頭に入れていたコメント行(-- Notion の「キャンプ道具リスト」の取り込み…)でした。コンソールは、コメント行だけの部分を「中身のない問い合わせ」と扱うようです。
その場ではコメント行を取り除いて実行し、あとでスクリプトのほうも、コメント行と空行を出さないように直しました。説明はSQLに書かず、スクリプトを実行したときに画面に表示する形にしています。
結果
開発でも本番でも、同じSQLで次のとおりになりました。
![取り込んだあとのギアの一覧。カテゴリごとに、製品名(メーカー)[コンテナ名]の形で並んでいる](/posts/hakozumi-07-notion-import/images/gears-list-imported.png)
取り込んだあとのギアの一覧(上のほうを切り出したもの)

Notionの「収納」から作られたコンテナ
画面は、この記事の時点のコードを手元で動かして撮ったものです。データは#7でNotionから取り込んだ、実際のギアを入れています。
| 項目 | 件数 |
|---|---|
| ギア | 56件(うち廃棄済 4件、コンテナに入っているもの 34件) |
| コンテナ | 6件(カーゴ 30L-1、カーゴ 30L-2、カーゴ 50L-1、コンテナ、テント、焚火台) |
本番の件数は、手元からは見ない方針なので、コンソールで件数を数えるSQLを実行して確かめました。
Notionの「収納」の選択肢には「カーゴ 50L-2」もありましたが、それが付いたギアが1つもなかったので、コンテナは作られませんでした。こういう「データを入れてみて初めて分かること」があるのも、実データを早めに入れてよかった点です。
おわりに
- 一度きりの取り込みは、画面ではなくスクリプトで
- 全件を消してから入れる形にして、何度でもやり直せるようにする
- D1のコンソールは、コメント行があると実行できない
これで、ハコヅミの中に実際のギア56件とコンテナ6件が入りました。次回は、このギアを使って、プランとチェックリストを作ります。