一覧へ戻る
ITSM

GlideRecordの配列操作:よくあるデータ重複(Duplication)の解決方法

ServiceNow開発者の皆様、GlideRecord のクエリ結果をループ(while)で配列(Array)に格納し、後からログ出力してみたら 「配列の中身がすべて同じデータ(最後に処理したレコード)に入れ替わっていた」 というトラブルに遭遇したことはありませんか? これはJavaScriptのオブジェクト参照の仕組みによる非常に有名な落とし穴です。ここでは、データが重複してしまう原因と、安全に配列へ格納するためのベストプラクティスを解説します。

なぜデータが重複(上書き)されてしまうのか?

  • gr オブジェクトなどを配列にそのまま push() した場合、システムは値そのものではなく、メモリ上の**オブジェクトの参照先(ポインタ)**を配列に保存します
  • while(gr.next()) で次のレコードに進むと、gr 自体の中身が書き換わっていくため、配列内に保存されたすべての参照先データも道連れになって最新のレコードデータへと変化してしまいます

データ重複の確実な解決策

配列にデータを保存する際は、GlideRecordのオブジェクト参照をそのまま入れるのではなく、プリミティブな値(純粋な文字列など)に変換してから格納することが鉄則です。

  • リストにする場合は必ず getValue() または getUniqueValue() の文字列で保持する
  • 複数のフィールド情報を持たせたい場合は、ループ内で毎回新しいオブジェクト {} を手動で生成し、そこにプリミティブ値をセットしてから push() する必要があります

実装コード例(アンチパターンと推奨策)

❌ アンチパターン(全ての値が最後に上書きされる危険な例)

var incidentArr = [];
var gr = new GlideRecord('incident');
gr.query();

while (gr.next()) {
    // 警告:GlideRecordオブジェクトの参照をそのまま配列に入れています。
    // ループ終了時、incidentArr の中身はすべて最後に読み込まれたレコードになります。
    incidentArr.push(gr); 
}

✅ ベストプラクティス(新しいオブジェクトを都度生成して格納する例)

var incidentArr = [];
var gr = new GlideRecord('incident');
gr.query();

while (gr.next()) {
    // 安全:ループの中で『毎回確実に新しいオブジェクト』を作成します
    var incObj = {
        sys_id: gr.getUniqueValue(),           // システムIDを正確に取得
        number: gr.getValue('number'),         // 値を純粋な文字列として取得
        state: gr.getDisplayValue('state')     // 人間が読める表示用ステータスを取得
    };

    // 参照ではなく、値が固定化された新しいオブジェクトを配列に入れます
    incidentArr.push(incObj);
}

// これで incidentArr の中にはレコードごとの正確なデータが重複せずに保存されます

まとめ

  • while(gr.next()) の中で gr オブジェクト本体をそのまま配列に push() してはいけません
  • データを後続の処理へ引き継ぎたい場合は、ループ内で都度 var obj = {} のように新規オブジェクトを生成する癖をつけましょう
  • 値を抽出する際は gr.number のような直接参照を避け、必ず getValue() などのAPIを併用して文字列に変換(キャスト)することが必須です

一言まとめ: 👉 配列への格納は gr 本体を避け、常にループ内で新しい {} を作り getValue() で値を入れよう!