code icon Code

Filter JSON Array

Filter items where field matches condition

Source Code

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

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

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

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

/**
 * Check if item matches the condition
 */
function matches(item, field, operator, value) {
  const fieldValue = getField(item, field);

  switch (operator) {
    case "eq":
      return String(fieldValue) === value;

    case "neq":
      return String(fieldValue) !== value;

    case "contains":
      if (Array.isArray(fieldValue)) {
        return fieldValue.some((v) => String(v).includes(value));
      }
      return String(fieldValue || "").includes(value);

    case "gt":
      return Number(fieldValue) > Number(value);

    case "lt":
      return Number(fieldValue) < Number(value);

    case "gte":
      return Number(fieldValue) >= Number(value);

    case "lte":
      return Number(fieldValue) <= Number(value);

    case "exists":
      const shouldExist = value === "true" || value === "1";
      const exists = fieldValue !== undefined && fieldValue !== null;
      return shouldExist ? exists : !exists;

    default:
      console.error(`Unknown operator: ${operator}`);
      process.exit(1);
  }
}

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(`Filtering ${items.length} items where ${field} ${operator} ${value}...`);

  const filtered = items.filter((item) => matches(item, field, operator, value));

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

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

  console.log(`\nāœ“ Filtered ${items.length} → ${filtered.length} items`);
  console.log(`  Condition: ${field} ${operator} ${value}`);
  console.log(`  Written to: ${outputPath}`);

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