FileMaker 追加のみインポート

FileMakerのデータベースを作る際、よく使う定番の小ネタ・小技があります。今回は追加のインポートです。

FileMakerではときどき「えっ。何でこんなことができないの?」っていう欠落(と感じること)があります。インポートのオプションに「一致しないレコードのみ追加する」がないこともそのひとつ。これがないせいでみんな大層困っています。困っていませんか?そうですか。私は困っていました。

インポート

インポートのダイアログには、「一致しないデータを新規レコードとして追加する」というオプションがあります。

照合フィールドで一致するレコードがなければ新規レコードとして追加してくれます。が、一致するレコードがあれば上書きしてしまいます。既存のデータに手を付けず一致しないデータだけを新規で追加することができません。そのような選択肢は用意されていません。なんてこったい。

長年、インポートダイアログは謎と不穏に満ちていました。「追加」以外の選択をしてまともな挙動になった試しがありません。大抵せっかくの既存データが上書きされてしっちゃかめっちゃかになります。常識で考えて既存データをホイホイ上書きするわけがないと思い込んでいたせいで事故にまみれました。それで、インポートダイアログの操作はトラウマとなり、ずっと逃げていました。

新しいバージョンでこのダイアログが改善されたと聞いて、やっとまともになるかと期待しましたが、見た目がちょっと変になっただけで不穏機能の怪奇は同じまま何の改善もありませんでした。寧ろややこしさに拍車がかかっただけとも言えます。

インポートダイアログの謎

そんなわけで冷静にこれが何なのかを改めて見ていきたいと思います。

追加 … 追加は最も簡単で安心、判りやすい選択です。問答無用に追加します。普通、インポートして追加すると言えばこれを指します。

対象レコードで一致するレコードを更新 または 更新 … 照合フィールドを調査して同じデータがあれば問答無用にすべてのフィールドを上書きします。もし同じデータがなければ新規に追加するチェック項目があります。

対象レコードの既存レコードを更新 または 置換 … インポートするデータで置き換えるということですが、これについて私は理解できておらず、何を目的に何をするものであるか、まるで判りません。てっきりフィールドを比較して既存レコードと一致していれば上書きして更新する機能だと思い込んでいました。でも違った。そっちは「更新」のほうでした。
FileMakerをバージョン1.5から使っていますがこれを実践して使ったことがありません。テスト的にやってみたことはありますが無茶苦茶になっただけで何が起きたのか意味不明でした。つまり、このオプションの存在意図すらわかりません。すいません。放置します。

もっと安倍晋三 猿にも判るくらい簡単にまとめるとこうなります。

  • 追加 レコードを追加します
  • 更新 照合フィールドが同じならフィールドを上書きします(同じものがなければ新規追加のオプションあり)
  • 置換 何もかもを無視して全部置き換えます(意味不明)

ということで、対象レコードで一致するレコードを更新 または 更新 というやつが重要なのでありますが、さっきも言ったように照合フィールドが同じならそのレコードのすべてを上書きしてしまいます。それがイヤならフィールドごとに「インポートしない」設定をします。しかしそうすると一致しないレコードを新規に追加したときフィールドにデータが入りません。意味ないじゃん。となります。

足りない選択肢

照合フィールドを見て、既存レコードがあるなら何もしない、なければ新規に追加 という選択肢がありません。最も需要がありそうに思えますし、自分は常にこれを望んでいました。何とか実現する方法ないでしょうか。

追加のみインポート

残念ながら簡単でスマートな方法はない、というか判りませんし知りません。強引に行くしかありません。その方法は多分、こうです。

ダミーの作業用テーブルを作成して必要フィールドを配置する

新規に作業用テーブルを作成し、ダミーとして使います。メインのテーブルでインポートを必要とするフィールドを再現します。

例えばこんなテーブルがあったとして、オブジェクトやファイルパスなどインポートしたいフィールドを作業テーブルにも作ります。

フィールド定義
メインのテーブル。オブジェクト、ファイル名、パス、サムネイルがインポートするフィールド
フィールド定義 - 作業用テーブル
作業用テーブル。インポートするフィールドを作成しておく

そしてインポートでは常に作業用テーブルに「追加」します。不穏な他の選択肢を使いません。シンプルに何も考えずごっそり追加します。

※ と、書きましたが、このあたり、後半で追記・改竄しています。ごっそり追加しません。後半をお読みください。

作業用テーブルを絞り込んで、それからメインにインポートする

作業用テーブルにフルで追加したので、あとはメインテーブルと比較するなどして、メインにないものだけを絞り込みます。

絞り込む方法はいろいろあるかと思います。適切なフィールドでリレーションを組むのも良いでしょう。リレーションを組めば*作業用テーブルにのみ存在するレコードを絞り込むことは容易です。

※ 適切なフィールドがなければ作成します。また、わざわざフィールドを作ってリレーションを組まなくても、スクリプトステップの中で計算やループを使いながら比較して絞り込んでいくこともできます。

※ もうひとつ、ダミーの作業用テーブルに一旦すべてインポートします。これが意味することは、いちいち時間が掛かりすぎるということです。ちょっとしたデータ量ならいいですが、画像を読み込んだりするタイプだったりすると目も当てられません。その辺の工夫も必要ですね。後半に追記しました。

 

ということで、何しろ作業用テーブルに全部ぶち込んでからメインと比較して、存在しないレコードだけをインポートするという、インポートを繰り返す流れです。

めっちゃ手間ですが今のところこれしか方法が思い浮かびません。

実作編:追加のみインポート

実際に使う時には、一連の作業をスクリプトで自動化したいものです。でも残念ながら汎用的なスクリプトに仕上げるのはちょっと難しい。データベースによって異なる不確定要素が多すぎるからです。

そこで、一例としてここではメディアデータベースを挙げてみます。

ここから先は、FileMakerメディア管理 実作編 Ver.2 サムネイル から繋がる話になります。メディア管理を実際に作って育てるシリーズです。実作編Ver.2のファイルはこちら。

FileMaker Document DownloadFM-FM_MediaDB_Ver2 .zip

[ 2021.07.21 追記 ] このファイルは投稿を公開後、後半の追記・変更と合わせてファイルを差し替えました。日付以前にダウンロードされた方は再度お願いします。

メディア管理でインポートするフォルダ管理

写真や動画などのメディアファイルを管理するデータベースを作成する実作編Ver.2 サムネイルの中で、フォルダ調査によるレコード追加スクリプトを追加したのでその説明も兼ねて具体的にいきます。

メディア管理のデータベースでインポートを使いたいといえば、それはもうフォルダごとメディアを読み込むことと相場が決まっております。

で、一度フォルダからインポートすればそれでお仕舞いかというとそんなことはありません。そのフォルダにはデータベースに登録した後にも画像ファイルが追加されたりすることでしょう。ときどき同じフォルダをチェックして「新規があれば追加で登録する」ということをしたいものです。フォルダを監視したいわけですね。

スクリプトで自動化の流れ

フォルダを監視し、未登録のメディアファイルがあれば追加で登録したい。それを実現するのは前段で書いたように次のような流れです。

ダミーの作業用テーブルを作り必要フィールドを設置し、フォルダごとインポート [ 追加 ] を実施して一旦見境なしに全部読み込みます。その後、メインのテーブルにないレコードだけを絞り込んで、それをメインにインポートします。用が済めば作業用テーブルの全レコードをポイと捨てます。

そしてここ追記ですが、もう一度やり直します。流れはこうです。

ダミーの作業用テーブルを作り必要フィールドを設置、フォルダごとインポート[ 追加 ]を施して、必要最低限のフィールドのみインポートします。この場合、必要最低限とは、ファイルパスです。あとせいぜいあっていいのはファイル名です。肝心のオブジェクトを放置します。その後、メインのテーブルにないレコードだけを絞り込んで残し、二度目のインポート[更新]を行います。今度はオブジェクトも含め必要なフィールドをすべてインポートします。「一致しないデータを新規レコードとして追加」のオプションを外して、今あるレコードだけを更新するのがミソです。これで作業用テーブルにはメインにないものだけがフルでインポートされました。そして、作業用テーブルのレコードをメインテーブルにインポート [追加]します。最後に用が済んだ作業用テーブルの全レコードをポイと捨てます。

重量軽減のための2度のインポート

追記する前は、作業用テーブルに「全部インポートする」と書いていましたが撤回しました。メディアを扱うことを考えると、ダミーテーブルにいちいち全部読み込むという前提はいただけません。インポートに時間がかかるし、無駄な容量も食います。どうせほとんどが捨ててしまう重複データなのに。

ですので1度目のインポートでは簡単なテキストファイルだけをインポートします。ファイルパスがあれば十分です。これなら、フォルダごと全てインポートしても大した浪費になりません。その後、メインとの比較を行い重複レコードを削除するなどして純粋に追加したいレコードだけを残します。その時点で改めてインポート[更新]で必要な分だけデータをフルでインポートします。

ということで、合計3度もインポートを行いますからスクリプトで自動化することは必須ですね。円滑に実施するため下準備をしておきましょう。

必要なフィールドはパスモドキ(フォルダ)です。それからパスモドキ(パス)です。なくてもいいけどあれば使い勝手の良い比較用チェック計算のフィールドも加えます。

パスモドキ(フォルダ)- フィルター機能とターゲットフォルダのパス用

スクリプトで自動化したいのだから、インポートもダイアログをオフって実行させたい。そのためには、どのフォルダをターゲットにするのかを計算式で命じなければなりません。命じるためにはあらかじめ特定する必要があります。ということで「そもそも」という話になりますが「フォルダを特定してから」「そのフォルダをターゲットに」スクリプトを動かすという前提を作っておきたいです。

そこで取った手段は、元々のメインレイアウト上で「特定フォルダ内のメディア」をフィルターしている状態でのみ、スクリプト実行のボタンが表示されるようにすることです。フォルダを監視したいのですから、フォルダでフィルターしている状態にあることは自然なことに思えます。

フィルターすることを実現するにはフィルター機能にフォルダを加えなければなりません。フォルダを簡単にフィルターするためには、値一覧にセットしておくのが理想、そのためにはフィールドとしてフォルダがないといけない。と逆から考えていった結果「フォルダ」フィールドを作っておくことになりました。

この「フォルダ」フィールドはパスに似たテキストで、言わばパスモドキ(フォルダ)です。少し整形すればパスの形にできます。パスの形になればしめたもの。スクリプト内で変数に仕込み、フォルダのターゲットにしてインポートの設定を作り自動化させることができます。

具体的には、FileMakerのパスからファイル名を取っ払ったものです。不確定要素の多い「file:」「image:」などのテキスト冒頭も取っ払ってます。

パスモドキ(パス)と比較のチェックフィールド – リレーション用

次は作業用テーブルとメインテーブルを正しく繋げるためのフィールドです。

別テーブルのレコード内容を比較したいとき、そこに必須なのはテーブル間で共通することと完全ユニークなデータフィールドであることです。共通していないと比較になりませんし、ユニークでないと照合が信頼できません。

メディア管理で照合のためのユニーク情報と言えばファイルパス以外にありません。しかしそれでは駄目なんです。FileMaker形式のパスは何故か知らんが「file:/」になったり「imagemac:/」になったり「file://」になったりして同じパスでも別の表記になります。とても照合に使えません。仕方なしに照合のためのパスモドキのフィールドを作成します。

パスモドキ(パス)フィールド

先ほどパスモドキ(フォルダ)を作りました。パスから「file:」の部分とファイル名部分を削ったフォルダまでを示すパスモドキです。こっちのパスモドキ(パス)は「file:」だけを取り除きファイル名が温存されたフルのパスモドキです。

さっきすっ飛ばしたのでパスモドキを作る計算式を一応載せておきます。尚、これ以降さきほどのパスモドキ(フォルダ)を「フォルダ」、こっちのパスモドキ(パス)を「パスモドキ」と呼びます。

GetValue ( Substitute ( ファイルパス ; [ "//" ; "/"] ; [ ":/" ; ¶] ) ; 2 )

FileMaker独自パスに見られる「// 」と「/」の混在をまず排除してから「:/」を改行に置換して二行目だけをゲットします。これでパスの中身だけ取得できて、共通ユニークデータとなります。これをリレーションで結びつけます。

パスモドキ

チェックフィールド

さらに作業用テーブルにチェックフィールド(計算)を作成します。

If ( パスモドキ = MediaDB::パスモドキ ; 0 ; 1 )

作業用テーブルのパスモドキとメインテーブルのパスモドキが等しければ 0 そうでなければ 1 を返すだけの簡単な計算です。

If ( IsEmpty ( MediaDB::パスモドキ ); 1 ; 0 )

作業テーブルから見て「メインテーブルのパスモドキがあれば」っていう、こういうのでもいいでしょう。何でもいいです。

チェックフィールドが 1 なら、作業用には存在しメインテーブルに存在しないレコードです。

1回目のインポートでファイルパスだけを全部インポートしていますから、チェックが1のレコードだけを残し、改めてフルでインポートします。今度は[更新]で、照合データがないものを追加しません。これで既存にないレコードだけがインポート完了しました。

メインテーブルに作業用レコードをインポート[追加]すれば目的完了。この後、インポートが終わった後作業用テーブルの全レコードを削除しておきます。

ここまでをすべてスクリプトにまとめ、途中3回出てくるインポートではあらかじめ設定を済ませターゲットを変数にしておくことで、ダイアログの表示もオフにできます。

このスクリプトにより、フォルダをチェックして追加があれば追加するという操作が一発でできるようになりました。フォルダの監視としても使えます。

フィールドかスクリプトか

フィールドを作ることに抵抗があるなら、スクリプト内だけでもやれます。リレーションも作りません。変数と計算式を駆使すればできます。

フィールドが増えてごちゃごちゃする代わりにスクリプトが簡素で済むか、スクリプトがごちゃごちゃ長くなるけどフィールドが少なく済むか、どっちかになりますね。お好みで。

フォルダ監視

メディア管理におけるフォルダ監視としてはまだ完成度は低いです。

例えば「元で更新されたファイルを読み込みたい」なんてありますね。そういうチェックは今回していません。あと、元フォルダから削除されたやつですね、それをデータベースからも削除したい。そういう希望もありますね。まだまだあります。今回は、元フォルダにて追加されたファイルのみを追加するインポートの話でございました。先は長いぜ。