code icon Code

Flatten Nested Arrays

Flatten nested arrays within objects

Source Code

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

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

if (!inputPath || !arrayField || !outputPath) {
  console.error("Usage: inputPath arrayField 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(`Flattening ${items.length} items by field: ${arrayField}...`);

  const flattened = [];

  for (const item of items) {
    const nestedArray = getField(item, arrayField);

    if (Array.isArray(nestedArray)) {
      // Create a new item for each nested element, combining parent fields
      for (const nested of nestedArray) {
        // Copy parent item without the nested array field
        const flatItem = { ...item };

        // Remove the nested array field from parent
        const fieldParts = arrayField.split(".");
        if (fieldParts.length === 1) {
          delete flatItem[arrayField];
        }

        // If nested is an object, spread its properties
        if (typeof nested === "object" && nested !== null) {
          Object.assign(flatItem, nested);
        } else {
          // If nested is a primitive, add it with a standard name
          flatItem[`${arrayField}_value`] = nested;
        }

        flattened.push(flatItem);
      }
    } else {
      // No nested array, keep item as-is
      flattened.push(item);
    }
  }

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

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

  console.log(`\nāœ“ Flattened ${items.length} → ${flattened.length} items`);
  console.log(`  Array field: ${arrayField}`);
  console.log(`  Written to: ${outputPath}`);

  console.log(
    JSON.stringify({
      success: true,
      outputPath,
      inputCount: items.length,
      outputCount: flattened.length,
      arrayField,
    })
  );
} catch (error) {
  console.error("Error:", error.message);
  process.exit(1);
}