GitHub

flattenObject()

Flatten nested objects into dot notation keys for easier access and manipulation.

Utility Function
Objects
Transformation
Syntax
flattenObject(obj, options)
Parameters

obj
Object

The nested object to flatten.

options
object
optional

Configuration options.

  • separator - Key separator (default: '.')
  • maxDepth - Maximum depth to flatten (default: Infinity)
  • includeArrays - Flatten arrays as well (default: false)
  • prefix - Prefix for all keys (default: '')
Returns

Object
- Flattened object with dot notation keys.

Examples

Basic Object Flattening

const nested = {
  user: {
    name: "John",
    profile: {
      age: 30,
      address: {
        street: "123 Main St",
        city: "New York"
      }
    }
  },
  settings: {
    theme: "dark",
    notifications: true
  }
};

const flattened = flattenObject(nested);
console.log(flattened);
// {
//   "user.name": "John",
//   "user.profile.age": 30,
//   "user.profile.address.street": "123 Main St",
//   "user.profile.address.city": "New York",
//   "settings.theme": "dark",
//   "settings.notifications": true
// }

Custom Separator

const config = {
  database: {
    host: "localhost",
    credentials: {
      username: "admin",
      password: "secret"
    }
  }
};

// Use underscore separator
const flattened = flattenObject(config, { separator: '_' });
console.log(flattened);
// {
//   "database_host": "localhost",
//   "database_credentials_username": "admin",
//   "database_credentials_password": "secret"
// }

// Use slash separator for path-like keys
const pathFlattened = flattenObject(config, { separator: '/' });
console.log(pathFlattened);
// {
//   "database/host": "localhost",
//   "database/credentials/username": "admin",
//   "database/credentials/password": "secret"
// }

Depth Control

const deepObject = {
  level1: {
    level2: {
      level3: {
        level4: {
          value: "deep"
        }
      }
    }
  }
};

// Limit flattening depth
const shallowFlattened = flattenObject(deepObject, { maxDepth: 2 });
console.log(shallowFlattened);
// {
//   "level1.level2": {
//     level3: {
//       level4: {
//         value: "deep"
//       }
//     }
//   }
// }

// Full depth flattening
const fullFlattened = flattenObject(deepObject);
console.log(fullFlattened);
// {
//   "level1.level2.level3.level4.value": "deep"
// }

Array Handling

const withArrays = {
  users: [
    { name: "Alice", age: 25 },
    { name: "Bob", age: 30 }
  ],
  tags: ["javascript", "nodejs"],
  metadata: {
    counts: [1, 2, 3],
    info: {
      total: 6
    }
  }
};

// Default: arrays are not flattened
const defaultFlattened = flattenObject(withArrays);
console.log(defaultFlattened);
// {
//   "users": [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }],
//   "tags": ["javascript", "nodejs"],
//   "metadata.counts": [1, 2, 3],
//   "metadata.info.total": 6
// }

// Include arrays in flattening
const arrayFlattened = flattenObject(withArrays, { includeArrays: true });
console.log(arrayFlattened);
// {
//   "users.0.name": "Alice",
//   "users.0.age": 25,
//   "users.1.name": "Bob",
//   "users.1.age": 30,
//   "tags.0": "javascript",
//   "tags.1": "nodejs",
//   "metadata.counts.0": 1,
//   "metadata.counts.1": 2,
//   "metadata.counts.2": 3,
//   "metadata.info.total": 6
// }

With Prefix

const appConfig = {
  api: {
    baseUrl: "https://api.example.com",
    timeout: 5000
  },
  ui: {
    theme: "dark",
    language: "en"
  }
};

const flattened = flattenObject(appConfig, { prefix: 'APP_' });
console.log(flattened);
// {
//   "APP_api.baseUrl": "https://api.example.com",
//   "APP_api.timeout": 5000,
//   "APP_ui.theme": "dark",
//   "APP_ui.language": "en"
// }

Environment Variables Generation

// Convert config to environment variables
const config = {
  database: {
    host: "localhost",
    port: 5432,
    ssl: {
      enabled: true,
      cert: "/path/to/cert"
    }
  },
  redis: {
    host: "localhost",
    port: 6379
  }
};

function configToEnvVars(config) {
  const flattened = flattenObject(config, { 
    separator: '_',
    prefix: 'APP_'
  });
  
  // Convert to uppercase and format for .env file
  const envVars = {};
  for (const [key, value] of Object.entries(flattened)) {
    const envKey = key.toUpperCase();
    envVars[envKey] = typeof value === 'string' ? value : JSON.stringify(value);
  }
  
  return envVars;
}

const envVars = configToEnvVars(config);
console.log(envVars);
// {
//   "APP_DATABASE_HOST": "localhost",
//   "APP_DATABASE_PORT": "5432",
//   "APP_DATABASE_SSL_ENABLED": "true",
//   "APP_DATABASE_SSL_CERT": "/path/to/cert",
//   "APP_REDIS_HOST": "localhost",
//   "APP_REDIS_PORT": "6379"
// }

// Generate .env file content
function generateEnvFile(envVars) {
  return Object.entries(envVars)
    .map(([key, value]) => `${key}=${value}`)
    .join('\n');
}

console.log(generateEnvFile(envVars));
// APP_DATABASE_HOST=localhost
// APP_DATABASE_PORT=5432
// APP_DATABASE_SSL_ENABLED=true
// APP_DATABASE_SSL_CERT=/path/to/cert
// APP_REDIS_HOST=localhost
// APP_REDIS_PORT=6379

Form Data Processing

// Process nested form data
const formData = {
  personal: {
    firstName: "John",
    lastName: "Doe",
    contact: {
      email: "john@example.com",
      phone: {
        home: "555-1234",
        mobile: "555-5678"
      }
    }
  },
  preferences: {
    newsletter: true,
    notifications: {
      email: true,
      sms: false
    }
  }
};

class FormProcessor {
  static flatten(data) {
    return flattenObject(data);
  }

  static validate(flatData) {
    const errors = {};
    
    // Validate email
    if (flatData['personal.contact.email'] && 
        !flatData['personal.contact.email'].includes('@')) {
      errors['personal.contact.email'] = 'Invalid email format';
    }
    
    // Validate phone numbers
    const phonePattern = /^\d{3}-\d{4}$/;
    if (flatData['personal.contact.phone.home'] && 
        !phonePattern.test(flatData['personal.contact.phone.home'])) {
      errors['personal.contact.phone.home'] = 'Invalid phone format';
    }
    
    return errors;
  }

  static process(formData) {
    const flattened = this.flatten(formData);
    const errors = this.validate(flattened);
    
    return {
      flattened,
      errors,
      isValid: Object.keys(errors).length === 0
    };
  }
}

const result = FormProcessor.process(formData);
console.log(result.flattened);
// {
//   "personal.firstName": "John",
//   "personal.lastName": "Doe",
//   "personal.contact.email": "john@example.com",
//   "personal.contact.phone.home": "555-1234",
//   "personal.contact.phone.mobile": "555-5678",
//   "preferences.newsletter": true,
//   "preferences.notifications.email": true,
//   "preferences.notifications.sms": false
// }

Configuration Search and Filter

// Search through complex configuration
const appSettings = {
  features: {
    authentication: {
      oauth: {
        google: { enabled: true, clientId: "google123" },
        github: { enabled: false, clientId: "github456" }
      },
      local: { enabled: true, minPasswordLength: 8 }
    },
    payments: {
      stripe: { enabled: true, publicKey: "pk_test_123" },
      paypal: { enabled: false, clientId: "paypal789" }
    }
  },
  ui: {
    theme: {
      default: "light",
      options: ["light", "dark", "auto"]
    }
  }
};

class ConfigSearch {
  constructor(config) {
    this.flattened = flattenObject(config);
  }

  search(query) {
    const results = {};
    const lowerQuery = query.toLowerCase();
    
    for (const [key, value] of Object.entries(this.flattened)) {
      if (key.toLowerCase().includes(lowerQuery) || 
          String(value).toLowerCase().includes(lowerQuery)) {
        results[key] = value;
      }
    }
    
    return results;
  }

  getByPattern(pattern) {
    const results = {};
    const regex = new RegExp(pattern);
    
    for (const [key, value] of Object.entries(this.flattened)) {
      if (regex.test(key)) {
        results[key] = value;
      }
    }
    
    return results;
  }

  getEnabled() {
    return this.getByPattern('\.enabled$');
  }

  getCredentials() {
    return this.getByPattern('(clientId|publicKey|secretKey)$');
  }
}

const configSearch = new ConfigSearch(appSettings);

// Search for "google" related settings
console.log(configSearch.search('google'));
// {
//   "features.authentication.oauth.google.enabled": true,
//   "features.authentication.oauth.google.clientId": "google123"
// }

// Get all enabled features
console.log(configSearch.getEnabled());
// {
//   "features.authentication.oauth.google.enabled": true,
//   "features.authentication.oauth.github.enabled": false,
//   "features.authentication.local.enabled": true,
//   "features.payments.stripe.enabled": true,
//   "features.payments.paypal.enabled": false
// }

// Get all credentials
console.log(configSearch.getCredentials());
// {
//   "features.authentication.oauth.google.clientId": "google123",
//   "features.authentication.oauth.github.clientId": "github456",
//   "features.payments.stripe.publicKey": "pk_test_123",
//   "features.payments.paypal.clientId": "paypal789"
// }