0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

kintoneの担当者別集計で件数が合わない理由|複数選択をJavaScriptで数える

0
Posted at

kintoneの案件数は3件なのに、担当者別グラフの件数を足すと4件になる。こんな場合は、集計の誤りと決めつける前に、1つのレコードが複数の分類に入る設計かを確認します。

この記事では、自社開発のダッシュボードプラグインの公開版1.1.4のコードを題材に、ユーザー選択フィールドを担当者別に分類する考え方を解説します。APIでレコードを取得する部分やグラフ描画は省き、取得済みの配列をどう数えるかに絞ります。

ユーザー選択のvalueは配列

ユーザー選択フィールドには、複数のユーザーを設定できます。値の形は公式のフィールド形式で確認できます。

const records = [
  { 担当: { type: 'USER_SELECT', value: [
    { code: 'a', name: '担当A' },
    { code: 'b', name: '担当B' }
  ] } },
  { 担当: { type: 'USER_SELECT', value: [
    { code: 'a', name: '担当A' }
  ] } },
  { 担当: { type: 'USER_SELECT', value: [] } }
];

この3レコードを「各担当者が関わる案件の件数」として数えると、担当Aが2件、担当Bが1件、未入力が1件です。分類ごとの合計は4件ですが、元レコードは3件です。

ここで4件を「ユニークな案件数」と呼ぶと混乱します。指標名を「担当者別の関与件数」とするなど、何を数えた値かを明示します。

Mapのキーは名前ではなくユーザーコードにする

名前だけをキーにすると、同名の別ユーザーを同じ分類へまとめてしまいます。ここではcodeをキー、nameを表示ラベルにします。

また、1つのレコード内で同じコードを複数回処理しないように、行ごとにSetを作ります。レコード全体で1つのSetを共有すると、担当Aが複数案件に関与していても1件にしか数えられなくなるため、作る場所が重要です。

教材コード:元の件数と分類の件数を分けて返す

// 教材用:取得済みのレコードを担当者別の関与件数に分類する。
function countByUser(records, fieldCode) {
  const groups = new Map();
  for (const record of records) {
    const field = record[fieldCode];
    if (!field || field.type !== 'USER_SELECT' || !Array.isArray(field.value)) {
      throw new Error(`ユーザー選択を確認してください: ${fieldCode}`);
    }
    const users = field.value;
    const keys = new Set(users.length ? users.map(user => user.code) : ['']);
    for (const code of keys) {
      if (typeof code !== 'string' || (users.length && !code)) {
        throw new Error('ユーザーコードを取得できません');
      }
      const user = users.find(user => user.code === code);
      if (!groups.has(code)) {
        groups.set(code, {
          code,
          label: code ? user.name || code : '(未入力)',
          count: 0
        });
      }
      groups.get(code).count += 1;
    }
  }
  const rows = [...groups.values()];
  return {
    recordCount: records.length,
    assignmentCount: rows.reduce((sum, group) => sum + group.count, 0),
    groups: rows
  };
}

上の例のrecordsと合わせて実行すると、次の結果になります。

const result = countByUser(records, '担当');
console.log(result.recordCount);     // 3
console.log(result.assignmentCount); // 4
console.log(result.groups);
// [
//   { code: 'a', label: '担当A', count: 2 },
//   { code: 'b', label: '担当B', count: 1 },
//   { code: '', label: '(未入力)', count: 1 }
// ]

recordCountは入力配列の長さです。同じレコードを重複して取得していない前提で使います。このコードがレコードIDの重複を取り除くわけではありません。

assignmentCountは、未入力の分類も含む分類件数の合計です。案件の総数とは分けて扱います。未入力を集計対象から除くかどうかも、業務のルールとして決めてください。

未入力と未取得を同じにしない

value: []は、ユーザー選択フィールドを取得できているが、誰も選ばれていない状態として扱います。一方、フィールド自体が存在しない場合は、コード・取得対象・閲覧権限などの確認が必要です。

教材では、フィールドがない場合や型が違う場合は停止します。未取得を「未入力」に混ぜると、権限や取得条件の問題を、未割り当て案件として数えてしまうためです。コード未取得も同様に停止します。

売上を担当者別に合計するときは、配分のルールも必要

件数だけでなく、1件100,000円の案件を担当A・担当Bの両方にそのまま集計すれば、担当別合計を足すと200,000円になります。

これは担当別の関与金額を見たいのか、会社の売上総額を見たいのかで意味が変わります。会社全体の売上総額を出したい場合は、担当者別の棒の合計ではなく、対象レコードの金額を1回ずつ集計します。

担当者ごとの売上配分が必要なら、主担当を1人に決める、明細や別フィールドへ配分額を持たせるなど、先にデータ設計を決めます。担当者の数で自動的に均等配分される機能を、この教材や紹介するプラグインが持つという説明ではありません。

公開製品のコードと照合した範囲

公開配布中のZIPからjs/core.jsを取り出し、ローカルの対象ファイルと一致することを確認しました。製品のaggregate()も、ユーザー選択の各要素を分類へ入れ、同じレコード内の分類キーをSetで重複除外しています。

教材コードと公開製品コードに対し、元3件と分類4件の違い、同一レコード内の同じコード、同名・別コード、空配列、未取得など、計10項目をNode.jsで確認しました。入力が不正な場合の停止処理は教材で追加した範囲もあり、製品と教材のすべての振る舞いが同一という意味ではありません。

この検証には実機kintoneへの変更やグラフ画面の試験は含みません。また、取得範囲・期間・権限・取得上限が違えば、分類以前に対象レコードの件数が変わります。比較するときは、対象レコードをそろえてから分類の違いを見ます。

画面で確認したい場合

自社で開発・提供しているダッシュボードプラグインでは、指標カード・グラフ・表を一覧画面上部へ配置できます。設定・利用画面と対応範囲は以下で確認できます。

ダッシュボードプラグインの画面・無料ZIPを見る

無料利用では、有償プランの案内バナーがPC・モバイルの一覧画面に30%の確率で表示されます。契約済みドメインには表示されません。利用前に、対応する項目・画面・取得上限を確認してください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?