FileMaker 作るメディア管理DBの話。メタデータを取得して専用メタテーブルに展開して利用します。ファイルメーカー内製の関数GetContainerAttributeを利用します。
前提として、メインのテーブルがすでにあってメディア管理が成り立っている状態です。IDがあり、オブジェクトフィールドがあります。そのオブジェクトフィールドに登録したメディアのメタデータを取得して利用するという話でございます。

メタデータの取得と利用
以前、FileMakerでメディア管理 – メタデータの取得で、取得をレベルに分けました。
LEVEL 1 何もしない
LEVEL 2 GetAsText
LEVEL 3 GetContainerAttribute
LEVEL 4 AppleScript
LEVEL 5 Exiftool
LEVEL 3 まではファイルメーカーの機能だけで実現できます。今回その LEVEL 3 GetContainerAttribute でメタデータを取得します。取得した後それを利用するところまで踏み込みます。
このポストはFileMakerメディア管理 実作編 Ver.4 付属の情報とも連動しています。
取得LEVEL 3
取得方法は簡単です。オブジェクトフィールドからメタデータをゲットする関数を使って計算させます。
GetContainerAttribute( オブジェクトフィールド ; "all" )
GetContainerAttribute all のデータを “all” で取得すると、下記ようにメタデータが網羅されます。
[General] Filename: IMGP4954.jpg Storage Type: File Reference MD5: 57AE7960CB988DEE7D3F4256F00C844C File Size: 8144885 Internal Size: 140 External Size: 8144885 External Files: 1 [Image] Width: 6000 Height: 4000 DPI Width: 72 DPI Height: 72 Transparency: 0 (False) [Photo] Orientation: 1 (Normal) Created: 2021/05/10 8:05:54 Modified: 2021/09/08 2:44:03 Latitude: Longitude: Make: RICOH IMAGING COMPANY, LTD. Model: PENTAX K-70
取得したメタデータの束を入れておくフィールドを追加しておきましょう。フィールドを使わず変数で済ませてもいいんですが、ここは分かりやすくフィールドにしておきます。

利用
ContainerAttAllフィールドに取得したこのデータ、このまま何もしなくても良いっちゃ良いんです。検索すればヒットするし、レイアウト上で広めに配置すれば内容を目視で確認できます。でもそんなのじゃ満足できないの。であればデータを加工してより利用しやすく仕上げましょう。どのようにしましょうか。ここではこうします。
- 別途専用テーブルにレコードとして展開します。
- 利用の際はポータルで表示します。まとめて表示したり、1行ポータルで利便性を得たりします。
- 特に重要と思える項目については、フィールドとして昇格させます。
では行きます。
専用テーブルに展開
取得したデータを専用テーブルに展開すると、完成形はこのようになります。これを作るのが最初の目的になります。

GetContainerAttributeで取得したテキストデータは、改行で区切られたリストです。それは概ね「 項目名: 値 」の形になっています。これを専用metaテーブルにレコード化します。
metaテーブルのフィールド
専用metaテーブルに必要なフィールドは次の通りです。
key と value
基本かつ重要なフィールドは key(項目)と value(値)です。コンピュータの世界というのは概ね項目と値でできています。世はすべてkeyとvalueなのです。これが宇宙を司るアイデンティティの砦です(何言ってんだこいつ)
group
取得したGetContainerAttributeのデータは、グループ分けがされています。上の例にある [General] や [image] がそれです。グループも生かしましょう。group フィールドを作りました。
type
今回はGetContainerAttributeの話をしていますが、先々は別の取得方法を使う予定もあります。そこで、type フィールドを作成し、取得元というか取得方法を記していきたいと思います。今回なら “GetContainerAttribute” または短く “GCA” です。
ID
リレーション用の ID フィールドです。必須です。メインのテーブルのIDでぶら下げます。
リレーション
メインテーブルの ID にぶら下がる専用テーブルは、1対多のリレーションってことになります。

一応、リレーション設定で自動作成を許可にしております。

こうしておくとポータルから手入力で追加できますからね。
リストをレコード化する
GetContainerAttributeで取得した内容をmetaテーブルにレコード化するスクリプトを作りましょう。
改行区切りのテキストを処理して別途テーブルにレコードとして展開させること自体はテンプレ的なループ処理です。行をレコードと見なし、1行ずつ処理してフィールドに転記していくという流れです。
処理部分では、改行テキストの規則制を見つけて上手に整形することが要になります。
改行テキストの規則制を見つける
GetContainerAttributeで取得したテキストを眺めればその規則性にすぐに気づきます。規則性を見つければ、それを利用することが出来ます。
GetContainerAttribute データの規則
- 改行されたリストになっている
- 空白行がある
- 先頭に [ ] で囲まれた文字列の行は、それ以下の行のグループを示している
- 項目と値の行は、セパレータを挟んで左側が項目、右側が値になっている
- セパレータは「 : 」
- 時間表示にも「 : 」が含まれているから、セパレータは「最初に登場する” : “」または「 “: “( : の後ろに半角スペースがある)」に限定される
空白行があるのであらかじめ排除しておいたほうがいいですね(¶&¶を¶にしてやればいいかな)
行の内容には二種類あることが判りました。[ ] のグループ名の行と、それ以外の “項目: 値” の行です。この規則を元にテーブルへの展開を発案します。
A. 「項目: 値」の行が、metaテーブルの1レコードになります。行ごとに新規レコードを作って転記していきます。
B. グループが書かれた行は新規レコードを作らず、「次のグループ名が登場するまでの共通のグループ名の値」として扱います。
スクリプトの流れ
1 事前にいろいろ変数を仕込んで準備
必要素材をすべて変数に入れておきます。
- 現在のメインテーブルでアクティブなレコードのIDを変数 $ID に保存
- GetContainerAttribute の処理だから、変数 $type に「GCA」と保存
- 処理するデータフィールドの内容を変数 $list に保存
変数を設定 [ $ID ; 値: メインテーブルのID ] 変数を設定 [ $type ; 値: "GCA" ] 変数を設定 [ $list ; 値: メタデータフィールド ]
2 metaテーブルを新規ウインドウで開く
変数の準備を整えたら、目的のmetaテーブルを新規ウインドウで開きます。新規ウインドウでなくてもいいんですが明確で分かりやすいのでそうしておきます。
3 $list をループで1行ずつ処理していく
ループで $list を1行ずつ処理していきます。改行リストをループで処理するには、
1. 最初に行数を調べ、
2. カウンタを設置します。
5. カウンタが行数を超えるまで処理を繰り返しますね。
ループの中身は
6. GetValue で「リストの ‘カウンタ’ 行目 」の行を特定し、
7. 処理を行います。
この流れはリストをループ処理するときのテンプレですね。肝心の処理については後ほど。
1. 変数を設定 [ $vc ; 値: ValueCount ( $list )] 2. 変数を設定 [ $c ; 値: 0 ] 3. Loop 4. 変数を設定 [ $c ; 値: $c + 1 ] 5. Exit Loop if [ $c > $vc ] 6. 変数を設定 [$gv = GetValue ( $list ; $c )] 7. 〜ここに肝心の処理〜 8. end Loop
ここで、慣れた人なら「カウンタが $i じゃなくて $c って何だよ馬鹿かこいつ」と思われたかもしれません。達人の間ではカウンタは $i と書くのが通例のようですね。はい。独学の悲しさ、counter の c で $c と書いてしまう癖が付いてしまい取れません💦
4 すべて終わったらウインドウを閉じて終わり
以上でおわりですが、この一連の処理を「いつどのように行うか」によって、根本的な分岐を作っておく必要があるかもしれません。
二度目以降の同じ処理のために
この措置、一度目ならいいんですが、二度目以降同じ処理を繰り返すと、テーブルに同じレコードがどんどん追加されていってマズいです。すでにデータがある場合スキップする条件を一番最初に付けておくのが良いと思います。
レコードのループ × リスト行のループを繰り返して「等しいとスキップ、差異があると上書き」の行程を踏むのが正統でしょうけど、面倒です。
幸い、今回は最初にデータを取得して GetContainerAttAll という名のフィールドに格納しました。GetContainerAttAll フィールドに取得したものと同じデータがすでにあればスキップする処理を最初に付けても良いですね。
更新する場合、レコードループ x 行ループ のチェックを避け、一旦metaテーブルの該当 type を全部消してから新規で処理するということも、ずぼらな私が好む手順です。
更新のチェックは、GetContainerAttAllフィールドの差異を確認する以外では、ファイル変更日などの日付情報フィールドを追加して日付で更新が必要かどうか見るというのもありです。
何しろ、重複レコードを生まないような工夫は必須でございます。
ということで、テンプレ的な流れは以上です。ここからは、さっき省略した肝心のループ処理について説明します。
行の処理
では 〜肝心の処理〜 の中身いきます。中身とは、行のレコード化です。
GetValue
まずは GetValue して行を特定するところから。GetValue ( 改行テキスト ; 行 ) と指定します。こちらにはすでにカウンタ$cがありますから、$c行目をいただけば良いです。変数 $gv に入れておきましょう。変数の名前についての苦情は受け付けません。
変数を設定 [ $gv ; 値: GetValue ( $list ; $c ) ]
行を特定できました。
行の中身には二種類あります。[ image ] などとグループが書かれた行と、項目: 値 の形になった行です。処理が異なりますので、if を使って動作を振り分けます。
if の条件は” [ “で始まっているかどうかを見ればいいと思います。 left ( left ; 1) = “[”
[ group ] の行
もし[ ] で囲まれたグループを示す行なら
グループ名を変数 $group にゲットします。” [ ” と ” ] ” はいらないから置換して消してしまいます。グループ名だけを頂いときます。それだけです。
変数を設定 [ $group ; 値: substitute ( $gv ; [ "[" ; "" ] ; [ "]" ; "" ] ) ]
項目: 値 の行
項目: 値 の行なら … ですけど他にないから「それ以外(else)」でいいですね。
ここでは次のことを行います。
1. $gv のセパレータを特定( “: ” ですね )
2. $gv のセパレータを改行に置換
3. $gv の1行目(項目名)を$keyに格納、2行目(値)を$valueに格納
4. metaテーブルに「新規レコード」作成
5. 溜め込んだ変数を各フィールドぶち込む
ID に $ID
type に $type
groupに $group
key に $key
value に $value
以上おわり。ここまで済むと End Loopに到達し、Loopの最初に戻ります。そうするとカウンタ$c に1が足され、$list の$c行目を対象に同じ処理を繰り返します。
最後の行まで処理が終わってloopの最初でカウンタ$cが$vcを超えた時点でループ終了。お疲れ様でした。
これでmetaテーブルにだーっとレコードが作成されました。
※ 作業を二重に繰り返さないための措置はここでは省略しました。

ポータルで表示
metaテーブルにデータがレコードとして収まりました。メインテーブルとは1対多の関係です。メインテーブルのレイアウト上にポータル表示で表示してみましょう。

このような網羅の形でもいいし、特定のkeyだけをフィルタすることも有効です。



少々仕込みに手間が必要ですが、ポップアップでKeyを選択して狙ったkeyだけ表示を絞り込むなんてインターフェイスもよく使います。

ポータル設定のフィルタに key=グローバル変数 の式を含める
metaテーブルのkeyの値を値一覧に作成
グローバルフィールドにポップアップで値一覧を表示
グローバルフィールドにModifyトリガで内容をグローバル変数に収めてポータルを更新
ということでレイアウト上にどのように表示するかは自由、metaテーブルは応用範囲も広いです。今は GetContainerAttribute の限られた key しかありませんが、ExifTool でゲットした大量のExifデータを網羅すればかなり本格的になりますよ。
フィールドに昇格
1対多のリレーションでは面倒なことが一つあります。メインテーブルのソートや検索などで値を利用することが気軽にできないことです。何かと使い勝手が悪かったりします。
そもそもで言いますと、ソートや検索やその他いろいろ駆使して頻繁に利用する重要データであるなら、metaテーブルの1レコードではなく、メインテーブルにフィールドとして作っておくべきです。
はい。ということで、メタデータの内いくつかをフィールドとして昇格させます。
IDで絞り込まれた状態のmetaテーブルのレコードをループで舐め回し、目的 key を見つければ value をメインテーブルの該当フィールドに転記します。このスクリプトスは上記「レコード化」に追記する形が望ましいです。メタデータを取得後、一気に処理できますから。

GetContainerAttributeで言えば「MD5」「Created」「Width」「Height」をそのような扱いにしています。
ここでもう一つ、もっと根源的なそもそもを言いますと、もし特定keyをいくつか欲しいだけなら、その項目を個別に取得すればいいんであって、メタデータの網羅もいらないしmetaテーブルも不要です。つまりこのポストの全否定ですが、ここでは「それが必要なんだ」という気持ちを尊重しておきました。