Airtable filterByFormulaでリンク先のレコードIDが0件になる原因と回避策

AirtableのAPIで、リンク項目(Link to another record)をレコードIDで絞り込もうとして、1件も返ってこないことがあります。データはあるのに0件が返るので、「該当するレコードが無い」と勘違いしやすい落とし穴です。
この記事では、原因と、弊社のAirtableで実際に確かめた結果、回避策をまとめます。
この記事の結論
- filterByFormula の数式の中では、リンク項目の値は「リンク先のレコードID」ではなく、「リンク先のプライマリフィールド(一番左の項目)の値」として扱われます。
- そのため
FIND('recXXXX', ARRAYJOIN({リンク項目}))は、データが何件あっても0件になります。 - 確実なのは、リンク先のレコードをIDで取得して、逆向きのリンク項目を読む方法です。
実際に確かめた結果
弊社のAirtable(顧客のテーブルと、その履歴のテーブルがリンクで結ばれている構成)で、読み取りだけで確かめました。テーブル名と値は伏せています。
| 探し方 | 返ってきた件数 |
|---|---|
リンク先のレコードID(recで始まる)で探すFIND('recXXXX', ARRAYJOIN({顧客})) |
0件 |
リンク先の表示名で探すFIND('表示名', ARRAYJOIN({顧客})) |
4件 |
| 顧客のレコードをIDで取得し、逆向きのリンク項目(履歴)を読む | 4件分のID |
同じ相手を指しているのに、IDで探すと0件、表示名で探すと4件でした。逆向きのリンク項目から読んだ件数も4件で、表示名で探した結果と一致しています。
弊社では、この書き方で「0件なら該当なし」と判断する処理が、本番に7か所ありました。どれもエラーにはならず、静かに「無い」と答え続けていました。
なぜこうなるのか
APIでレコードを取得すると、リンク項目はレコードIDの配列で返ってきます。
{
"id": "recAAAAAAAAAAAAAA",
"fields": {
"顧客": ["recBBBBBBBBBBBBBB"]
}
}
一方、filterByFormula は、Airtableの画面で使う数式と同じように評価されます。数式の中でリンク項目を参照すると、画面に表示されている値、つまりリンク先のプライマリフィールドの値が並んだものとして扱われます。ARRAYJOIN で文字列にしても中身は表示名なので、レコードIDは含まれていません。
「APIの返り値ではID、数式の中では表示名」という食い違いが、0件の正体です。Airtableのコミュニティでも、filterByFormula ではレコードIDではなくプライマリフィールドの値を使う必要がある、と繰り返し説明されています。
回避策
1. 逆向きのリンク項目から読む(おすすめ)
Airtableでテーブル同士をリンクすると、相手のテーブルにも逆向きのリンク項目ができます。探したい相手のレコードをIDで1件取得すれば、そこに、自分を指しているレコードのIDが並んでいます。
GET https://api.airtable.com/v0/{baseId}/{顧客テーブル}/{顧客のレコードID}
"fields": {
"履歴": ["recCCCCCCCCCCCCCC", "recDDDDDDDDDDDDDD"]
}
そのIDのレコードの中身が必要なら、RECORD_ID() を使って取得します。RECORD_ID() はそのテーブル自身のレコードIDを返すので、この比較は正しく当たります。弊社でも、この書き方で指定した2件がそのまま返ってくることを確かめています。
OR(RECORD_ID()='recCCCCCCCCCCCCCC', RECORD_ID()='recDDDDDDDDDDDDDD')
APIの呼び出しは1回増えますが、表示名の重複や名前の変更に影響されません。
2. 表示名で探す場合は、区切り記号で挟んで完全一致にする
表示名で探すときに FIND('山田', ARRAYJOIN({顧客})) のように書くと、「山田商事」のような別の相手まで当たります。区切り記号で前後を挟むと、名前がまるごと一致したときだけ当たります。
FIND(',山田商事,', ',' & ARRAYJOIN({顧客}, ',') & ',')
弊社の確認では、表示名の先頭2文字だけで探すと、挟まない書き方は4件当たり、挟む書き方は0件になりました。
ただし、この方法には次の弱点があります。
- 同じ表示名の相手が複数いると、区別できません。
- 表示名にカンマが含まれていると崩れます。区切り記号は、名前に出てこない文字に変えてください。
- 相手の表示名を変更すると、当たらなくなります。
3. リンク先のレコードIDを数式項目で持たせる
リンク先のテーブルに数式 RECORD_ID() の項目を作り、元のテーブルにその項目のルックアップ項目を作る方法もあります。ルックアップ項目にはリンク先のレコードIDが並ぶので、IDで探せるようになります。Airtableのコミュニティで紹介されている方法です。
FIND('recBBBBBBBBBBBBBB', ARRAYJOIN({顧客のレコードID}))
テーブルに項目を足すことになるので、既存の運用やフォームに影響がないかを先に確かめてください。
4. 件数が少なければ、取ってから絞る
レコード数が少ないテーブルなら、条件を付けずに取得して、プログラムの側でIDを含むものだけ残す方法もあります。APIは1回に最大100件ずつ返すので、offset を使って最後まで読みます。
const hits = records.filter(r => (r.fields['顧客'] || []).includes('recBBBBBBBBBBBBBB'));
n8nで使うときの注意
n8nのAirtableノードで「Filter By Formula」を使う場合も、式はAirtableのAPIに渡されるので、同じように0件になります。結果が0件でもエラーにはならず、後ろのノードが動かないまま成功扱いで終わるので、気づきにくくなります。
0件が返ってきたら、「データが無い」と決めつけずに、まず式の書き方を疑ってください。
まとめ
- 数式の中のリンク項目は、レコードIDではなく表示名として扱われます。
- だから
FIND('recXXXX', ARRAYJOIN({リンク項目}))は0件になります。 - 確実なのは、相手のレコードをIDで取得して、逆向きのリンク項目を読む方法です。
- 表示名で探すなら、区切り記号で挟んで完全一致にします。
参考
- filterByFormula using link record id(Airtable Community)
- List records where Linked Field contains Record ID(Airtable Community)
- Formula field reference(Airtable Support)
Airtableとn8nでつくる仕組みのご相談
「データはあるのに0件になる」「知らないうちに処理が止まっている」といった不具合の点検や、Airtableとn8nを使った業務の自動化の仕組みづくりをお引き受けしています。






