code icon Code

Extract Fields

Extract specific fields from each object in a JSON array

Source Code

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

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

if (!inputPath || !fieldsArg || !outputPath) {
  console.error("Usage: inputPath fields 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;
}

/**
 * Parse field spec: "field" or "field:alias"
 */
function parseFieldSpec(spec) {
  const [source, alias] = spec.split(":");
  return {
    source: source.trim(),
    target: (alias || source).trim(),
  };
}

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);
  }

  const fieldSpecs = fieldsArg.split(",").map(parseFieldSpec);
  console.log(
    `Extracting fields: ${fieldSpecs.map((f) => f.source + (f.target !== f.source ? ` → ${f.target}` : "")).join(", ")}`
  );

  const extracted = items.map((item) => {
    const result = {};
    for (const { source, target } of fieldSpecs) {
      const value = getField(item, source);
      if (value !== undefined) {
        result[target] = value;
      }
    }
    return result;
  });

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

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

  console.log(`\nāœ“ Extracted ${fieldSpecs.length} fields from ${items.length} items`);
  console.log(`  Written to: ${outputPath}`);

  // Show sample
  if (extracted.length > 0) {
    console.log(`  Sample (first item):`);
    const sample = extracted[0];
    for (const [key, value] of Object.entries(sample)) {
      const display =
        typeof value === "string" && value.length > 50
          ? value.slice(0, 50) + "..."
          : JSON.stringify(value);
      console.log(`    ${key}: ${display}`);
    }
  }

  console.log(
    JSON.stringify({
      success: true,
      outputPath,
      count: extracted.length,
      fields: fieldSpecs.map((f) => f.target),
    })
  );
} catch (error) {
  console.error("Error:", error.message);
  process.exit(1);
}