データベース作成のコツ: Notion 解説(8)

はじめに

YUKA'S STUDIO 繋がりの Rei さんの紹介で、Notion Meetup Kyoto Vol 2に参加してきました。セッション後の交流会でも、たくさんの情報をいただきました。関連するネタは後日紹介していきたいと思います。

交流会でいろいろな話が出た中で日本語でデータベースの説明が書かれたものは、あまりないということでした。Notion 界隈はかなり賑わっていますが、確かにタスク管理を改善するような話ばかりで、あまりデータベースべったりな紹介はあまり見ない気がします。YouTube などだとタスク管理をどうするといった方がビューを稼げますしね。

Notion を使ってみて、データベースの使い勝手に満足はしていますが、PostgreSQL などの一般的な Relational Database とは考え方を変えないといけない部分があるので、それが説明できればと思ってこの記事を書きます(どうせ普段からマニアックな話しか書いていないので、問題ないと思いますし)。

背景

比較対象は Rails で作成した森高千里さんのデータベースです。このデータベース設計は、単一テーブル継承(STI)を使ったりと、かなりガッツリ設計したものです。今回、このページを Notion に移植しました。データはまだ移行途中ですが、ほとんどの機能は実現できたと思います。現在のページのリンクを貼っておきます。今はまだ Notion のリンクになっていますが、独自ドメインに展開する方法を昨日教えてもらったので、正式公開時には上の moritaka-ml のドメインの下で展開します。

データベースで注意する点

Notion のリレーションは多対多

Relational Database の場合は基本的に、1対多のリレーションを作ることがほとんどです。Rails でいうと関連を貼る側(子側)が belongs_to で親側にリンクを貼ります。親からは、has_many で1対多の関連を得るか、has_one で1対1の関連を得ます。なぜこんな感じになっているかというと、基本的に belongs_to 側で相手側のデータに関する責任を持つ必要があるためです。多くのプログラミング言語では、実態が存在しなかったり、削除されて消えてしまった NULL オブジェクトに対して、メソッドを送るとエラーになったり、例外処理が発生したりします。こういうことが起こらないように、関連が消えた時にどうするのかなどを細かくプログラムする必要があります(リレーションだけを削除したり、子供全部を削除したりなど)。

一方、Notion のリレーションは多対多となっています。関連を貼ると相手側からも逆にアクセスできるリレーションが作成されます。このため、どちらが親という考慮は必要ありません。また、関連データが存在しない属性に対して、Formula などを実行しても無視するだけでエラーになったりしません。この辺りは、昔の Objective-C のように nil にメソッドを送っても問題が起こらなかったのに似ています。ユーザは存在しない関連データに関して特殊な処理をする必要がありません。このあたりはうまく考えられていると思います。

Rollup は 1 段まで

Notion のリレーションはあくまで相手のページが参照できるだけで、リレーションだけでは相手のページの Name または Name の配列しか表示されません。これを拡張するものが Rollup です。Rollup を使うことによって、関連先のページの属性を引っ張ってくることができます。

ただし、ここに注意が必要で Rollup で引っ張ってこれるのは、あくまで相手のページのオリジナル属性だけとなっています。Table 1 と Table 2 のリレーションを作成した時、Table 2 に Table 1 の属性を Rollup で表示することは可能です。しかし、新しい Table 3 を Table 2 にリレーションしても、Table 2 に表示されている Table 1 の Rollup 属性は表示することはできません。

Relational データベースでは、リレーションの責任を分断するために正規化をすることが必要となります。ただし、Notion の場合にはこの Rollup の制約があるため、重複した関連を持つ必要があります。上記の例では本来作る必要のない、Table 3 から Table 1 へのリンクが必要となります。こうするとデータの入力漏れが問題になりますが、Notion では後述する View と Filter をうまく設定することで入力を簡易化できるので、ページの作り込みで回避が可能でした。このあたりは後日開設できればと思います。

テーブルに複数のデータを統合し、単一テーブル継承(STI)を使う

Rollup の制限もあり、あまり細かく正規化することが難しくなります。そこで、できるだけ共通のデータを持つものを一つのテーブルにまとめることが重要になります。せっかくなので、先ほどのデータベースの例を使って解説します。

先ほどのアーティストのページだと、曲一覧を登録するデータベースとして「SetList」というものを用意しています。Rails ではアルバムやシングルなどの曲一覧とコンサーはの曲一覧は別テーブルにしていました。今回はこれを一つの SetList というテーブルにしてみました。こうすることで、曲(Song) → コンテンツ(Contents) → セットリスト(SetList) という関連を複製しなくてすみました。こうすることで、曲ごとのページでは、SetList がどちらに繋がっているかを判断することで View を分けることができました。

データベース本体は直接編集せず、必要な情報を Filter して Linked Database で表示・編集

STI するとどうしてもテーブルが大きくなります。昨日の交流会でも Excel のようなウインドウ枠の固定が欲しいという話が出ていました。しかし、Notion の場合にはこのような大きなテーブルは直接編集するべきではありません。テーブルはデータベース置場のようなところにこっそり隠しておくことをお勧めします。先程のデータベースではトップページの一番下にデータベース置場という Toggle page がこっそりとあり、さらにその先のページリンクだけが貼ってあります。

一番説明しやすいのが活動一覧なので、このページで解説します。このページには、Toggle page で以下のページが掲載されています。これらの雑多のデータは単一の Activities というテーブルで管理しています。このテーブルは非常に雑多な属性ばかりなので、選んで入力するのは面倒です。Notion の場合、Linked Databse で必要な属性だけを表示できるので、それを使います。この際、データを Filter しておくと、新規データは Filter で設定された属性は自動的に設定済になります。このテクニックを使うと、正規化できていないリレーションでも属性設定忘れがなくなります。また、その場に必要ないデータを間違って編集しないという点でも有効だと思います。

  • CM
    f:id:hkob:20210315080013p:plain
    CM
  • テレビ番組 (レギュラー)
    f:id:hkob:20210315080046p:plain
    テレビ番組(レギュラー)
  • ラジオ番組 (レギュラー): データが入っていないので省略
  • テレビ番組
    f:id:hkob:20210315080133p:plain
    テレビ番組
  • ラジオ番組: データが入っていないので省略
  • 書籍
    f:id:hkob:20210315080227p:plain
    書籍
  • 雑誌: データが入っていないので省略
  • 主題歌
    f:id:hkob:20210315080257p:plain
    主題歌
  • 映画
    f:id:hkob:20210315080752p:plain
    映画
  • その他のイベント: データが入っていないので省略

入力したいページの Toggle を開いて、必要な情報を入力するだけで済むのは非常に効率が高いと思います。

テンプレートで要らない情報を隠す

(3/16 追記) テーブルが大きくなると、各ページを編集するときに余計な属性が出てきて面倒です。そこで、目的ごとにテンプレートを別途用意すると余計なものが見えなくなります。例えば、前述の「Set List」の場合、こんな感じで二つのテンプレートを用意しています。

f:id:hkob:20210316065923p:plain
二つのテンプレート
これらのテンプレートの属性部分はこんな感じになっています。Hide 6 properties となっており、常時表示しているのは「# of contents」だけです。ここで、複数個のリンクが表示される「Contents」「Songs」「Performances」は邪魔なので「Always hide」で常に隠されています。残りの属性は「Hide when empty」で値がない時だけ隠れるようになっています。「Device」はアルバムやビデオなどが接続されている時だけ表示され、「Concert」はコンサートが接続されている時だけ表示されます。自動で表示・非表示が選択されるのは楽ですね。
f:id:hkob:20210316070103p:plain
テンプレートの属性部分

Set list (Concerts) の本体はこんな感じです。セットリストの曲目一覧、このセットリストがどの会場で演奏されたか、同じコンサートで使われた別のセットリストが自動的にリンクされます(一部追加でフィルタに値を入れる必要があるものもあります)。

f:id:hkob:20210316070754p:plain
Set list (Concerts) のテンプレート

もう一つの方も同じような感じで、アルバムなどに対応したテンプレートになっています。この辺りは単一テーブル継承でサブクラスを作っているイメージですね。

おわりに

Relational データベースを普段使っているユーザから見た Notion のデータベース機能で気になることをまとめてみました。多対多でいろいろと面倒になる点を Filter などで、うまく作り込んでいるなと感じました。一般的なユーザに使わせるにはいい設計だと思いました。朝思いついて、通勤電車の中で簡易的なまとめた記事ですが、どなたかの役に立てばと思い執筆しました。Twitter などでご意見いただけると幸いです。

P.S.

このデータベースは 1994 年の末ごろに始めたものでした。webarchive でも 2 台目の頃のサーバのデータしか残っていませんでしたね。当時は Perl のスクリプトで HTML を直接記載していました。懐かしい。当時はこんなに Web が使われるとも思っていませんでした。 1999年3月のアーカイブ


はてなブログに書いた Notion 記事一覧