営業やマーケティングの担当者から、こんな依頼を受けたことはないでしょうか。
「代理店経由で接点を持ったコンタクトだけリストにしたい」 「複数のキャンペーンに接触している人を抽出したい」 「スプレッドシートに書き出して、キャンペーンごとの内訳を見たい」
レコードの詳細画面を開けば、紐づいているキャンペーンは一覧で表示されています。データはHubSpotの中にある。それなら難しくないはずだ、と思って作業を始めます。
ところが、ワークフローで関連レコードの値を持ってこようとすると、選択肢が「最初に関連付けたレコード」と「最も最近関連付けたレコード」しかありません。3件紐づいていても、取得できるのは1件だけです。
リストの絞り込み条件を見ても、関連レコードのプロパティは出てきません。レポートビルダーでも同じです。
結果として、こういう対応になりがちです。
これは設定ミスではありません。HubSpotの仕様上の制約です。ただし、回避する方法があります。
HubSpotは関連付けを順序でしか識別していません。「1番目」「最後」という位置は指定できますが、「2番目」や「特定の条件に合うもの」を指す手段が標準では用意されていません。
そして標準のリストやレポートは、基本的に1つのレコードを1行として扱う設計になっています。1件のコンタクトに3件のキャンペーンが紐づいているという「1対多」の関係を、1行の中に展開する仕組みがありません。
つまり課題の本質は、データが無いことではなく、1対多の情報を1行で扱える形に変換する手段が無いことです。
先に確認しておきたいことがあります。やりたいことによっては、標準機能で解決します。 ここを飛ばしてコードを書くと、不要な保守対象を抱えることになります。
「紐づく契約の件数」「関連する商談の金額合計」のように、数を数えるか合計するだけなら、計算プロパティのロールアップ機能で対応できます。コードは不要です。
「主キャンペーンの名前だけ欲しい」「初回接触のものだけ欲しい」といった場合、関連付けにラベルを付けるのが有効です。
先に触れたとおり、HubSpotは関連付けを順序でしか識別できません。逆に言えば、ラベルという別の識別軸を用意すれば、順序に依存せず狙った1件を指定できるようになります。「主キャンペーン」「初回接触」といったラベルを運用ルールとして定義するほうが、コードよりも保守が軽く済みます。
集約したい値の種類が限られていて、今後増えないなら、複数のチェックボックス型プロパティを使う方法があります。ワークフローの「レコードを編集」には、複数チェックボックスに対して既存の値を消さずに追加する設定があるためです。
ただし選択肢を事前に登録しておく必要があるため、外部システム連携などで値が増え続ける場合には向きません。
上記に当てはまらない場合、つまり
このときに、ワークフローのカスタムコードを使います。以降がその方法です。
考え方はシンプルです。関連レコードの情報を、親レコードのプロパティ1つにまとめて保持しておく。
コンタクトに「累積キャンペーン名」というプロパティを用意し、紐づく全キャンペーン名を区切り文字でつないで格納します。
テキストのプロパティになった時点で、HubSpotの標準機能がそのまま使えるようになります。
| できること | 具体例 |
| リストで絞り込む | 「累積キャンペーン名に『代理店』を含む」でコンタクトを抽出レポートの軸にする |
| レポートの軸にする | 接触キャンペーンの組み合わせパターン別に件数を集計 |
| 書き出す | スプレッドシートやCSVに、紐づく全件を含めて出力 |
| 一覧で確認する | ビューの列に追加し、レコードを開かずに把握 |
管理者側の変化としては、「その依頼はHubSpotの仕様上できません」と答える場面が減るのが実際のところだと思います。一度作れば、以降の類似依頼は標準機能の範囲で対応できます。
手順に入る前にここを押さえておくと、後で作り直しになりません。運用してみると効いてくる部分です。
いちばん自然に見えて、いちばん壊れやすいのが追記型です。関連付けが増えたときに、既存の値へ名前を足していく方式です。2つの理由で必ず実態とズレます。
そこで、処理が走るたびに関連レコードを全件読み直し、文字列をゼロから作り直す方式にします。何回実行しても同じ結果になるため、ズレが原理的に発生しません。追加にも解除にも自動で追従します。
処理量は増えますが、後述のとおり実務上のコストはわずかです。正しさが自動で保たれる設計を選ぶほうが、長期的には安く済みます。
CSVやスプレッドシートに書き出したときに列が割れます。値そのものにカンマが含まれている場合、元の区切りが復元できなくなります。|(縦棒)や ;(セミコロン)を使ってください。
APIの一時的なエラーなどで取得件数がゼロになったとき、そのまま書き込むと蓄積していた値を空で上書きしてしまいます。「取得ゼロなら何もしない」という分岐を1つ挟んでおいてください。
親オブジェクト(例:コンタクト)に、値を格納するプロパティを作成します。
累積キャンペーン名作成後、内部名を控えてください。設定 > プロパティ から該当プロパティを開くと表示されています。
HubSpotのプロパティには、画面表示用のラベルとシステムが使う内部名の2つがあります。コードが受け付けるのは内部名だけです。日本語ラベルで作成すると内部名がローマ字になることが多く、推測は当たりません。必ず実物を確認してください。
コードに埋め込む値を先に集めます。
| 必要なもの | 具体例 |
関連オブジェクトのID(2- で始まる数字) |
設定 > オブジェクト、または設定画面のURL |
| 集約したいプロパティの内部名 | 設定 > プロパティ で該当オブジェクトを選択 |
プロパティ一覧画面の「エクスポート」を使うと、ラベルと内部名の対応表がまとめて取得できます。内部名は今後も必要になるので、1回落としておくと以降が楽です。
設定 > 連携 > Private Apps から新規作成し、次のスコープ(権限)を付与します。
crm.objects.contacts.read)crm.objects.custom.read)片方だけでは動きません。 関連レコードを取得する処理は、親と子の両方の読み取り権限を参照しています。ここは実際につまずきやすい箇所です。
書き込み権限は不要です。プロパティへの反映は、後続の「レコードを編集」アクションが行うためです。必要最小限の権限に絞るという観点でも、読み取りのみに留めてください。
作成後に表示されるアクセストークンを控えます。なお、後からスコープを変更するとトークンが変わる場合があります。その際は次のStepで登録した値も更新してください。
親オブジェクト(コンタクト)ベースのワークフローを作成します。
トリガーは「関連レコード数の変更」にします。
親オブジェクトに、関連レコードの件数を数えるロールアップ計算プロパティ(例:関連キャンペーン数)を作り、「この値が変更されたとき」を登録条件に設定します。
関連付けの追加でも解除でも件数が変化するため、どちらのケースでも自動的に発火します。方針1の「解除に追従する」を成立させているのは、この仕組みです。
再登録(同じレコードが条件を再度満たしたときに再度登録する)はオンにしてください。
シークレットの登録
アクション内の「シークレット」で、Step 3のアクセストークンを登録します。ここで付けた名前が、そのままコード内で参照する名前になります。 HS_TOKEN として登録したなら、コードでは process.env.HS_TOKEN と書きます。名前が一致していないと認証エラーになります。
コードに含めるプロパティ
空のままで構いません。このコードは親レコードのIDだけを使い、必要な情報はAPI経由で取得します。
コード
冒頭の設定部分だけ、環境に合わせて書き換えてください。
| 処理 | 役割 | 省略できるか |
ページング(while (after)) |
関連が500件を超える場合に続きを取得 | 件数が少なくても残しておく |
| 100件ずつの分割 | 値の一括取得は1回100件が上限 | 省略不可。101件で停止します |
if (!body.results) |
エラー応答を検知して原因をログに出す | 残す。切り分けの手間が変わります |
| 重複除去と並び替え | 同じ文字列が安定して生成されるようにする | 突合に使うなら残す |
| 文字数の上限処理 | プロパティの上限を超えないようにする | 残す |
出力フィールドの定義
アクション下部の「データ出力」で、ruisekikyanpenmeiを文字列型として追加します。
コード側で値を返していても、このフォームで宣言しないと後続アクションから参照できません。「出力フィールドで定義されていません」という注意が表示されていたら、この設定が漏れています。
カスタムコードの後に、2つのアクションをこの順番で置きます。
累積キャンペーン名 にruisekikyanpenmeiを設定する順番が重要です。分岐を先に置くことで、方針3で触れた「空で上書きしてしまう」事故を防げます。
関連レコードが2〜3件紐づいているレコード1件で実行し、実行履歴のログを確認します。
確認ポイント1:3つの件数がそろっているか
関連=3件 / 値取得=3件 / ユニーク=3件
関連=3件 / 値取得=0件 → プロパティの内部名が違う、またはスコープが足りません関連=3件 / 値取得=1件 → 一部のレコードでプロパティが空欄になっています(データ側の課題)関連=3件 / ユニーク=2件 → 同じ値のレコードが重複しています(想定どおりか確認)確認ポイント2:解除したときに値が減るか
関連付けを1件解除して再実行し、値が3件から2件に減ることを確認してください。
これが「作り直し方式」になっているかを確かめる唯一のテストです。 ここで減らない場合、追記型になっているか、トリガーが解除を拾えていません。追加のテストだけで済ませると、この不具合は本番稼働から数か月後に「数字が合わない」という形で発覚します。
管理者・情報システム部門の立場から、稼働後に関わってくる点をまとめます。
ワークフローは即時実行ではありません。加えてトリガーに使うロールアップ計算プロパティの更新にも時間がかかります。関連付けの操作から反映まで、数分程度の遅れを見込んでください。
「今すぐ画面で確認したい」という用途には向きません。リストやレポート、定期的な書き出しといった用途が適しています。
1回の実行で消費するAPIコールは、関連レコード100件あたり1回+関連取得の1回です。関連が3件のコンタクトなら2回で済みます。
Private AppのAPIコール数には1日あたりの上限があります。通常の運用で問題になることはまずありませんが、初回に既存データへ一括適用する場合は件数を確認してください。数万件のコンタクトを対象にする場合、日を分けて実行するなどの配慮が必要です。
なお、カスタムコードには実行時間の上限があります。1レコードに数千件が紐づくケースがある場合は、事前にテストしてください。
Private Appのアクセストークンは、発行者と保管場所を決めておいてください。担当者の異動時に「誰が発行したか分からない」状態になると、スコープの変更や再発行ができなくなります。
読み取り権限のみに絞っておけば、万一の漏洩時の影響範囲も限定されます。Step 3で書き込み権限を付けない理由はここにもあります。
この仕組みは、コード冒頭の設定値さえ分かれば誰でも保守できます。逆にそれが不明だと、コードを読み解く作業が発生します。次の表をドキュメントとして残しておくことを勧めます。
| 記録項目 | 例 |
| ワークフロー名 | 【コンタクト】累積キャンペーン名の更新PARENT_OBJ |
PARENT_OBJ |
contacts |
CHILD_OBJ |
2-227687479(キャンペーン) |
NAME_PROP |
campaign_name(キャンペーン名) |
| 格納先プロパティ | ruisekikyanpenmei(累積キャンペーン名) |
| シークレット名 | HS_TOKEN |
| Private App名 / 発行者 | 累積プロパティ更新用 / 情報システム部 |
| トリガー用プロパティ | 関連キャンペーン数(ロールアップ計算プロパティ) |
同じ仕組みを他のオブジェクトへ展開するときも、この表を複製して値を差し替えるだけで済みます。
実行履歴のログに出る内容から、原因を特定できます。
| ログに出る内容 | 原因 | 対処 |
MISSING_SCOPES / 403 |
権限不足 | Private Appに親・子両方の読み取り権限を追加 |
Authentication credentials not found / 401 |
トークンが無効 | トークンを再取得し、シークレットの値を更新 |
OBJECT_NOT_FOUND / 404 |
IDが違う | オブジェクトIDとレコードIDを確認 |
Cannot read properties of undefined |
エラー応答を受け取っている | オブジェクトIDとレコードIDを確認 |
値取得=0件 |
プロパティの内部名が違う | 設定 > プロパティ で内部名を再確認 |
| 出力が後続で選べない | 出力フィールドの宣言漏れ | 「データ出力」フォームに追加 |
コード内の if (!body.results) によるエラー確認とログ出力は、稼働後も消さずに残してください。何か起きたときに、実行履歴を見るだけで原因が絞れます。設定変更やHubSpot側の仕様変更があったときに、ここが効いてきます。
同じ考え方は、オブジェクトとプロパティを差し替えるだけで転用できます。
また、values.join() の部分を変えれば、集約の内容自体を変更できます。
ロールアップ計算プロパティでは条件を細かく指定しづらい場面があります。「集計はしたいが、条件が標準機能の枠に収まらない」というときに、この形が使えます。
HubSpotの標準機能は「1レコードに1つの関連先」を前提に設計されています。複数紐づく情報を扱いたい場面では、集約した結果をプロパティとして保持しておくことで、リストもレポートも書き出しも、いつもの操作の範囲で扱えるようになります。
進める順番は次のとおりです。
実装そのものは1つのワークフローで完結します。関連レコードの情報が扱えないことで手作業や確認作業が発生しているなら、検討する価値のある方法です。
自社の環境で適用できるか判断がつかない場合や、どの方法が適しているかを整理したい場合は、お気軽にご相談ください。