code icon Code

Group JSON Array

Group array items by field value

Source Code

import fs from "fs";
import path from "path";

const [inputPath, field, outputPath] = process.argv.slice(2);

if (!inputPath || !field || !outputPath) {
  console.error("Usage: inputPath field outputPath");
  process.exit(1);
}

/**
 * Get nested field value using dot notation
 */
function getField(obj, fieldPath) {
  const parts = fieldPath.split(".");
  let value = obj;
  for (const part of parts) {
    if (value == null) return undefined;
    value = value[part];
  }
  return value;
}

try {
  console.log(`Reading ${inputPath}...`);
  const raw = fs.readFileSync(inputPath, "utf-8");
  const data = JSON.parse(raw);

  const items = Array.isArray(data)
    ? data
    : data.items || data.results || data.messages || [];

  if (!Array.isArray(items)) {
    console.error("Input must be a JSON array or object with array property");
    process.exit(1);
  }

  console.log(`Grouping ${items.length} items by ${field}...`);

  const groups = {};
  for (const item of items) {
    const value = getField(item, field);
    const key = value != null ? String(value) : "(empty)";

    if (!groups[key]) {
      groups[key] = [];
    }
    groups[key].push(item);
  }

  const groupCount = Object.keys(groups).length;

  // Ensure output directory exists
  const dir = path.dirname(outputPath);
  if (dir && dir !== ".") {
    fs.mkdirSync(dir, { recursive: true });
  }

  fs.writeFileSync(outputPath, JSON.stringify(groups, null, 2));

  console.log(`\nāœ“ Grouped ${items.length} items into ${groupCount} groups`);
  console.log(`  Grouped by: ${field}`);
  console.log(`  Written to: ${outputPath}`);

  // Show group summary
  const groupSummary = Object.entries(groups)
    .map(([key, items]) => ({ key, count: items.length }))
    .sort((a, b) => b.count - a.count)
    .slice(0, 5);

  console.log(`  Top groups:`);
  for (const { key, count } of groupSummary) {
    console.log(`    - ${key}: ${count} items`);
  }
  if (groupCount > 5) {
    console.log(`    ... and ${groupCount - 5} more groups`);
  }

  console.log(
    JSON.stringify({
      success: true,
      outputPath,
      totalItems: items.length,
      groupCount,
      field,
    })
  );
} catch (error) {
  console.error("Error:", error.message);
  process.exit(1);
}