FileMaker 作るメディア管理DB、分類ごとにフィルターする仕組みについての詳細です。
このポストは FileMakerメディア管理 実作編 Ver.4 付属の情報を補完する内容でもあります。ここで取り上げるフィルタ機能は実作編v4の機能に準じます。
このページ内の見出し
フィルターの機能
レコードを分類ごとに項目で絞り込みます。
動きはこんな感じです。分類を選んでから項目を選択すると一発で絞り込まれます。複数の項目では、いずれかを含む(or)検索になります。
実際のファイルを試して動きを確認してみてください → FileMakerメディア管理 実作編 Ver.4 付属の情報
性能
高性能ではありません。分類内の項目を or でフィルタします。or と and を明示的に使い分けることはできません。分類をまたがって複合処理することもできません。
その代わり分類ごとにフィルタを記憶させます。前に選択していた分類を選び直すとフィルタ状態が復帰します。
インターフェイス
分類を選択するメニューから選んで

出現する項目を選択するとレコードが絞り込まれます。

以上が機能の概要で、これをどのように実現したかという話になります。
こんなこと言うのもどうかと思いますが、強引で雑な仕組みです。洗練された見事な仕組みとは到底言えません。ですので今後どう変化していくかわかりません。実作編 ver.4 時点での詳細であるにすぎないとお断りしておきます。
もっと洗練された良いフィルター方法を教えてくれればありがたいです。
フィルターの仕組み
概要
フィルタする項目の値一覧を作り、その値一覧から専用テーブルにレコードを作り、そのテーブルをポータルに表示して、ポータル行にボタンを設置して、ボタンクリックにより行のアイテムを取得して検索を実行します。
検索実行の際に、現在のフィルターと、現在のレコードリストをグローバル変数に保存しておき、後に同じフィルター分類を選択したときに結果を復帰させます。
なぜポータル
フィルタ機能と言いながら実際はただ検索するにすぎません。なのに、わざわざ別テーブルのポータルを利用するのはなぜでしょう。
そんなことをするつもりは当初ありませんでした。チェックボックスセットを使えばいいだけなんです。それで何ら問題ありません。
ただ一点のみ、チェックボックスセットには重大な欠陥があります。項目が少ないうちはいいですが、増えたときにスクロールをしてくれず、表示しきれません。これは致命傷。
ポータルなら縦に並べるしかないとはいえ、スクロールできます。ただそれだけの理由で、めちゃめんどい工程を踏んで別テーブルのポータル表示となりました。
webビューアでも作ってみたんですよ。折りたたみとか、自由に作れますからね。そのやりかたも悪くなかったんですが、HTML と CSS とscript を必死で書きながら、ふと「あほくさ」と思ってしまい、もしかしたらより面倒になったかもしれない別テーブル、ポータル、行選択といった小技を選択することになりました。
分類 = フィールド、項目 = フィールド内容
フィルターする分類はフィールドです。フィルターする項目はそれらフィールドの内容です。キーワードフィールドの「猫」とか、拡張子フィールドの「jpg」が項目です。
値一覧
フィルタに利用したいフィールドの値を値一覧に作ります。これにより項目をリストすることができます。
値一覧の名前にはルールを設け「フルのフィールド名」としています。例えばMediaDB::拡張子の値一覧なら名前は “MediaDB::拡張子”です。
専用テーブル FilterItems
フィルターのためだけに専用テーブルを追加しています。FilterItemsテーブルには、値一覧の値をレコード化します。
スクリプト「フィルター項目の更新」を用意して、常に更新できるようにしておきます。スクリプトについては後ほど。
フィールド
taxonomy … 分類名( = フルフィールド名 = 値一覧名 )
Label … ラベル(分類名の表示上のラベル)
name … 分類の項目。nameを選択することでフィルタを実行する
ONOFFtoggle … 論理値が入る数値フィールド
FMファイル名 … グローバルフィールド(リレーションのために使用する *)
portalFilter … グローバルフィールド(ポータルフィルタ用)
* メインテーブルに「このファイルの名前」というグローバルフィールドがあって、それとリレーションさせる。共通点がFMファイル名、つまり実質制約なしのリレーション。

ポータル portalFilter
値一覧の項目を選択する方法として、ポータルを利用します。
ポータルフィルターをこのように設定します。
FilterIems::taxonomy = FilterItems::portalFilter
「taxonomy(分類名)が○○」のレコードを表示するフィルタ設定です。○○には都度、taxonomy名=フルフィールド名=値一覧名が入ります。portalFilter がグローバルフィールドだからです。どうやって入れるか、ボタンで入れます。
フィルターメニューのボタン

フィルターを選択するメニューのボタンに、スクリプト「フィルタ選択ボタン」を割り当てます。スクリプト引数に、”フルフィールド名” を仕込みます。このスクリプトについても後ほど。
フィルターの保存と復帰
複合検索ができない代わりに、フィルター選び直し時に以前のフィルター結果を再現するため、以下の機能をフィルター選択ボタンのスクリプトに付け加えています。
- フィルターを実行すると、そのとき選んでいたフィルター分類名と、結果のIDリストをグローバル変数に保存
- 再度フィルターを選んだときにグローバル変数が存在していれば結果IDを復元
スクリプト
フィルター項目を更新
FilterItemsテーブルに項目をレコードとして作成するスクリプトです。
項目はレコードを編集することで随時変化します。例えば新しいキーワードを追加した、何かを削除した、常に変更されます。こちらのテーブル内容も合わせて変更されなければなりません。
1 全削除してから作り直す
いちいち変更をチェックして更新させるのも面倒なので、更新が必要なときにこのスクリプトが実行されると、最初に「全部削除」してから速攻で「全部追加」するようにしました。ずぼら更新ですいません。
2 値一覧の内容をゲットしてレコード化
改行テキストをレコード化する処理はテンプレ的動作です。FileMaker メディア管理 – メタデータの取得と利用(LEVEL 3 編)にも詳しく書きました。似たような流れになります。
ここでは、値一覧の値をレコード化していきます。二重のループになっています。
1 ValueListNames で、すべての値一覧の名前を改行区切りでゲットします。
選んでいる隙はないので、ファイル内の値一覧名をすべてゲットします。
2 ゲットした名前リストから、フィルターに関係する値一覧名だけを残します。
フルフィールドの名前を採用したのはここで抽出しやすいためでもあります。名前の中に「::」が入っている値一覧名なんて他にありません。ここまでで「フィルタに必要な値一覧名(フルフィールド名書式)のリストが手に入りました。
3 名前リストをループで回し、ValueListItems で、値一覧の値をゲットします
値一覧名(=フルフィールド名)のリストをループで回し、ValueListItems つまり値の改行リストをゲットします。
4 値一覧の値リストでループを回し、新規レコードとして追加していきます
値の改行リストをゲットしたので、ここからLoop内Loopを回し、値一行ずつ、つまり値そのもの処理します。親ループの値一覧名と現ループの値を新規レコードのそれぞれフィールド(値一覧名をtaxonomyに、値をname)にぶち込みます。
これにて、空のFilterItemsテーブルに、taxonomyとnameが、だーっと作られました。

ポータルフィルタ選択ボタン
フィルタ選択ボタンのスクリプトです。ボタンごとにスクリプト引数をセットして使います。引数はフルフィールド名(フィールド = 値一覧名 = taxonomy )です。
スクリプトの仕事は次の2つ。
1 ポータルフィルタを外部から操作してポータルの表示を変更する
2 ポータルフィルタが切り替わった時、以前の記録があればフィルタ結果を再現する
ポータルの表示を変更する
FilterItemsのレコードを表示するポータルには「portalFilter」とオブジェクト名を付けてあります。
フィルタ設定は「FilterItems::taxonomy = FilterItems::portalFilter」でしたね。グローバルフィールドFilterItems::portalFilter に、引数(フルフィールド名 = 値一覧名 = taxonomy)をぶち込みます。
忘れずに「ポータルの更新 [ “portalFilter” ] を行うことで、ぶち込まれたフィールドだけの値がポータルに並びます。
フィルタ結果を再現する
ポータルの表示が切り替わった時、以前の記録があれば再現します。以前の記録というのはこの後で述べますが、グローバル変数 $$portalFlter_フィルタ名_IDs です。この変数にフィルタ結果のIDが記録されているので再現します。再現方法は、馬鹿丁寧に検索モードでIDリストのIDをすべて新規検索条件に入れて検索します。もうちょっとスマートなやりかたがあるような気もしますが・・・
グローバル変数 $$portalFlter_フィルタ名_IDs については、このあとすぐ。
ポータルフィルタ 行を選択するボタン
ポータルの中で、項目(つまり行)を選択したときに実行されるスクリプトです。
FilterItemsテーブルの name フィールドが配置されて、ボタン化されています。このボタンにスクリプト「ポータルフィルタ 行を選択するボタン」が割り当てあられています(横のチェックマークは表示のためだけの飾りボタンです)
1 必要なデータを変数に保存
クリックすると、フィルタ名、ポータル行番号、name を変数に保存し、ONOFFトグルで0または1が記録されます。
2 選択された行の name を変数に保存
or 検索に対応するため、クリックでフィルタは動作しません。まず、ON(1)である行の name をリストとして記録します。ちょっと面倒ですがポータル行をループで舐め回して記録していきます。
3 name リスト分の新規検索条件で検索
その後、name リストが1行以上あれば、検索します。検索モードにしてnameを回し新規検索条件を追加していき、検索します。
これで見事フィルタされました。
引き続き、この検索結果を保存しておきます。
4 検索結果を記憶
そういや説明していなかった気がしますが、メインテーブルには「IDs」という集計フィールドがあります。現在の対象レコードのIDを記録する優れたフィールドです。
検索結果を保存するわけですが「へんすうづくり」を利用します。へんすうづくりて何やねん。はい。変数を名前で作成する小技です。→ FileMaker 変数を名前で設定
変数名は「$$portalFilter_現在のフィルタ名_IDs」です。値は IDs です。現在の対象レコードのIDリストです。
「すべて表示」みたいに、フィルターをすべてご破算にする行為を行ったときには、こうした変数をすべて削除するステップを踏みます。そうでない限り、グローバル変数は記録されっぱなしになります。次回、同じフィルタ名でフィルタした際、グローバル変数が存在すれば IDs から結果が再現されます。
その他のスクリプト
その他いくつかスクリプトがあります。
例えば、フォルダに関するフィルタは例外的な措置を追加しています。フォルダ階層を選択してフィルタできます。
トグルで「隠す」が入れ替わる選択ボタンと解除ボタンがフィールド上にあります。「フィルタ」ボタンのスクリプトは通常のフィルタと似たような動きですがこのボタン専用です。
階層上のフォルダは特にリストされていないのでポータル表示との連動がなく、まあまあ雑な実装です。
ほんというと、フォルダに関しては全く別の扱いにしたいのであまり踏み込んでいません。

ということで、最後のほうは雑な仕組みと雑な説明になってしまいましたが、フィルターに関する詳細でした。
実際のファイルがこちらからダウンロードできます。