関連レコードで表示させた値の合計を別フィールドで表示させたい。

関連レコードで表示させた値の合計を別フィールドで表示させたいと考えております。

編集や追加の際に実行したら問題ないと思うのですが別アプリの関連レコードでこの合計値を表示させているので編集ボタンを一回押さないと値が更新されず困っています。

いちいち編集ボタンを押して更新するのではなく常に最新の状態をするための方法はありますでしょうか。

キンコミから抜粋引用
(JavaScriptそのものも含む)はイベントドリブンといって、何かのイベント(例 特定のボタンを押すなど)が発生しないと動き出さない作りです。

なので、一覧画面上に釦を準備して この釦の押下げにより
全てのレコードを「一括更新」させるのが現実的ではないでしょうか

但し!Kin さんの投稿から
わかるとおり、レコード数が多くなる
1日に実行できるAPIリクエスト数を超える、懸念がありますので注意してください

APIリクエスト数を気にしなくてもいい方法を思いつきました!

Aアプリ---関連レコードで表示させた値の合計を
別フィールドで表示させたいアプリ
❶集計値フィールドを設ける
(※関連レコード一覧はあっても、なくても可)

Bアプリ---関連レコード一覧の集計値を出力するアプリ
①関連レコード一覧フィールドを設ける
参照するアプリは、自アプリ=Bアプリ(このアプリ)】
②暫定の合計フィールドを設け、ここに 一旦 自動集計する
③保存「釦」の 押下げをトリガーにして、②の値を❶にPush入力する

これにより、Bアプリの更新値は 常にAアプリに反映されるとおもいます

※②③共に実装可能なPluginなら知っていますので
JS,CSS(=カスタマイズ)でも可能ではないでしょうか?

ご返信ありがとうございます。
ボタンを設置する必要があるのですね…

わがままかもしれませんが、プラグインもなるべく使用したくないです。
ボタンもあまり設置したくないですね。

ボタンもあまり設置したくないですね。

新たな「釦」設置の必要ないです!

③保存「釦」

は、デフォルトの釦です…なので

❶Bのアプリで関連レコードで表示させた値の合計を別フィールドで表示させ
(=自アプリの関連レコード一覧の集計をする)
(※「表示するレコードの条件」はAアプリの設定と同じ)

❷❶の値のみを、Aのアプリへ同期させる
(=「保存」がトリガー)

と云う、カスタマイズをされたらいかがでしょう

神谷さんの最初のお考えは、Aアプリのカスタマイズだと思うのですが
自分の考えは、Bアプリのカスタマイズとなります
ですが、最終的な表示は同じになります。

Plugin ≒ カスタマイズ(JS,CSS)
Pluginで出来ることは、ほぼカスタマイズでも可能でしょう
(外部サーバが必要になるような場合を除いて)


kintone のみで何かしらの処理を定期的に動かす機能はありません。

フィールドに保存しなくて良い (つまり、レコード詳細画面を開いたときだけ見れればよい) のであれば、スペースに合計値を表示すれば良いと思います。フィールドに保存する必要があるのであれば、外部サーバーなどで定期的にデータを更新する必要があります。

もしくは、関連レコードで表示している先のアプリでレコード保存時に、合計を計算してレコードに書き込む…とかですかね。。

ふゆき様の考えだと毎回保存ボタンを押す必要があるということでしょうか。
私の説明不足もあり申し訳ありません。 :sob:

現状やりたいこととしては、作業時間の合計を出力したいです。
Aアプリ: タスクアプリ
Bアプリ: 工数アプリ
Cアプリ:プロジェクトアプリ
とします。

Aアプリでは作業時間の履歴を関連レコードで出力しています。(Bアプリから取得)
そこでタスクの作業時間の合計を出したいのです。

タスクの作業時間の合計を出すことでCアプリでタスクごとの作業時間を関連レコードで取得できるので。
Cアプリでの作業時間の合計はtextContentで追加しています。

現状の仕様としてはBアプリで工数を追加したときにrest apiでBアプリ内の同じタスクIDを持つものを取得し作業時間を合計してそれをAアプリに出力しています。

この仕様の問題としては過去のレコードはタスクアプリで更新されないところです。

何か良い方法はないでしょうか…

関連レコードで表示している先のアプリでレコード保存時に、合計を計算してレコードに書き込む…とかですかね。。

現状後者を採用しております。

ただここで今悩んでいるのが過去のレコードが更新されないことです。
新しく追加した際は問題なく動きますが、過去のレコードは一回保存しなおす必要があるので…

結構量が多いため手作業は現実的ではないです。 :sob:

こういったとき住田さまならいかがいたしますか?

問題の切り分けとして、処理を行いたいタイミングを考えると良いと思います。

  1. リアルタイムで処理を動かしたい
  2. 定期的 (週1や月1) で処理を動かしたい
  3. (新しい機能を追加したときなど) 過去のデータに対して 1. や 2. で実現される変更を加えたい

1.や2.で毎回全レコード更新を行うと、データが蓄積されていくにつれて処理時間もAPIコール数も無限に消費していくので、いつか破綻する可能性があります。そのため、対象のレコードを絞る必要があります。 (例えば、保存ボタンを押したレコードに対してのみ実施、過去1か月間のレコードのみ実施、など)

3.については、タイミングとしては1回きりなので、全レコードを更新しても影響は起きにくいです。私はこの場合、CSV取り込みや手元で全更新するプログラムを書いて行うことが多いですね。

今回相談されているのは 3. のケースだと思っていますが、いかがでしょうか?

おっしゃる通りです。

CSV取り込みや手元で全更新するプログラムを書いて行うことが多いですね。

こちらは具体的にどのような方法なのでしょうか。

プログラムで行う処理が明確になっているのであれば、処理後にどのようなレコードが出来上がっているかも想像がつくはずです。そのデータを Excel 等で準備すれば問題ないです。

この場合、

  1. Aアプリ、BアプリからレコードをCSVエクスポートする
  2. Excel に取り込んで SUMIFDSUM 関数を使ったり、 PowerQuery を用いてAアプリのレコードごとに合計時間を計算する
  3. CSV形式で保存して kintone にインポートする

といった手順で行えばいいと思います。

上の例では Excel を利用しましたが、 JavaScript でもやることは同じだと思います。

1 Like

弊社はカスタマイズ禁止なので...
自分の考え方に間違えがないか、持ち駒(Plugin)で検証してみました

検証内容
①「工数アプリ」に【タスクID】【工数】を入力 後、保存(=レコードの新規作成)
②「タスクアプリ」を 立上げ、一覧画面で ①入力した工数の反映を確認する

結果---添付画像の通りです

こちらは何というプラグインを使用しておりますか?

また、プラグインを使用しない方法はやはりないですかね?
素のキントーンの機能では難しいでしょうか。

緑色の線は
「他アプリ更新プラグイン」(Ribbit’s works/完全無料)です
Web頁から抜粋
当プラグインはオープンソースです。 プラグインがどういったファイルで構成されているのか、どのように実装されているのか、全てのプログラムを Github から確認することが可能です。
なので、解析が出来るならJS、CSSに置き換えできるかもしれませんね
但し、89.1%がタイプスクリプトで書かれているみたいです

添付---:backhand_index_pointing_up:今回の検証設定 ご参考まで!

赤色の線は
ATTAZooですが、カスタマイズなら フィールドを1つ減らすことが可能でしょうから
こちらはご自身で書くことをお勧めします

要はこの図と同じ挙動ができればいいのでしょうか?

「カスタマイズで転記」の部分は

  1. 複数のレコードを取得するで、タスクアプリから[タスクID]が同じレコードを取得。
  2. 取得したレコードの[実績_総工数]に[現在までの総工数]の値をコピーして更新

で、できると思います。

「カスタマイズで集計する」の部分も、[タスクID]一致のレコードを取得して
取得したレコードの[工数入力]の和を[実績工数]に入れるだけです。

(() => {
  'use strict';

  const TASK_APP_ID = 1; // タスクアプリのアプリIDに書き換える

  // 工数アプリのレコード追加が成功したときに処理開始
  kintone.events.on('app.record.create.submit.success', async (event) => {
    const record = event.record;
    const taskId = record['タスクID'].value;
    const totalEffort = record['現在までの総工数'].value;

    try {
      // タスクアプリで同じ[タスクID]のレコードを検索
      const query = `タスクID = ${taskId}`;
      const getResponse = await kintone.api(
        kintone.api.url('/k/v1/records', true),
        'GET', 
        {
          app: TASK_APP_ID,
          query: query
        }
      );

      if (getResponse.records.length > 0) {
        const recordId = getResponse.records[0].$id.value;

        // 検索結果のレコードを更新
        await kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', {
            app: TASK_APP_ID,
            id: recordId,
            record: {
              '実績_総工数': {
                value: totalEffort
              }
            }
          }
        );
      } else {
        console.log('一致する[タスクID]がタスクアプリにありません');
      }
    } catch (error) {
      console.error('タスクアプリでのAPI呼び出しエラー:', error);
    }

    return event;
  });

  // 工数アプリのレコード追加画面で[タスクID]の値が変わったときに処理開始
  kintone.events.on('app.record.create.change.タスクID', (event) => {
    const record = event.record;
    const taskId = record['タスクID'].value;

    // タスクIDが未入力なら処理を中止
    if (!taskId) return event;

    try {
      // 同じアプリ内で[タスクID]一致のレコードを検索
      const query = `タスクID = ${taskId}`;
      kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {
        app: kintone.app.getId(),
        query: query,
        fields: ['工数入力']
      }).then((getResp) => {
        // 検索結果のレコードの[工数入力]の合計を計算
        const totalEffort = getResp.records.reduce((sum, rec) => {
          const value = parseFloat(rec['工数入力'].value);
          return sum + (isNaN(value) ? 0 : value);
        }, 0);

        // 計算結果を[実績工数]に入力
        record['実績工数'].value = totalEffort;
        kintone.app.record.set(event);
      }).catch((err) => {
        console.error('[工数入力]の取得エラー:', err);
      });
    } catch (err) {
      console.error('工数計算中のエラー:', err);
    }

    return event;
  });
})();
1 Like

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。