Skip to main content
The dot notation module provides utilities for working with Firestore’s dot notation syntax, which allows updating nested fields without replacing entire objects.

Core Functions

isDotNotation

Checks if a key uses dot notation syntax.
function isDotNotation(key: string): boolean

Parameters

key
string
required
The key to check for dot notation

Returns

boolean
boolean
Returns true if the key contains a dot (.) character, false otherwise

Example

import { isDotNotation } from '@spacelabstech/firestoreorm' // dotNotation';

isDotNotation('address.city');  // true
isDotNotation('name');          // false
isDotNotation('user.profile.bio'); // true

hasDotNotationKeys

Checks if an object contains any keys with dot notation.
function hasDotNotationKeys(obj: Record<string, any>): boolean

Parameters

obj
Record<string, any>
required
The object to check for dot notation keys

Returns

boolean
boolean
Returns true if any key in the object uses dot notation, false otherwise

Example

import { hasDotNotationKeys } from '@spacelabstech/firestoreorm' // dotNotation';

hasDotNotationKeys({
  name: 'John',
  'address.city': 'LA'
});  // true

hasDotNotationKeys({
  name: 'John',
  age: 30
});  // false

Conversion Functions

expandDotNotation

Converts a flat object with dot notation keys into a nested object structure.
function expandDotNotation<T = any>(
  flatObj: Record<string, any>
): T

Parameters

flatObj
Record<string, any>
required
Object with dot notation keys to expand into nested structure

Returns

T
object
Nested object structure with expanded dot notation paths

Example

import { expandDotNotation } from '@spacelabstech/firestoreorm' // dotNotation';

const flat = {
  'address.city': 'Los Angeles',
  'address.zip': '90001',
  'address.country': 'USA',
  name: 'John Doe'
};

const nested = expandDotNotation(flat);
// Result:
// {
//   address: {
//     city: 'Los Angeles',
//     zip: '90001',
//     country: 'USA'
//   },
//   name: 'John Doe'
// }

flattenToDotNotation

Converts a nested object into a flat object with dot notation keys.
function flattenToDotNotation<T = any>(
  obj: Record<string, any>,
  prefix?: string
): Record<string, any>

Parameters

obj
Record<string, any>
required
Nested object to flatten into dot notation
prefix
string
Internal prefix for recursion. Leave empty when calling directly.

Returns

Record<string, any>
object
Flat object with dot notation keys

Behavior

  • Only flattens plain objects
  • Preserves arrays, dates, and other special types as values
  • Does not flatten objects with custom prototypes

Example

import { flattenToDotNotation } from '@spacelabstech/firestoreorm' // dotNotation';

const nested = {
  address: {
    city: 'Los Angeles',
    zip: '90001',
    country: 'USA'
  },
  name: 'John Doe',
  tags: ['customer', 'premium'],
  createdAt: new Date('2024-01-01')
};

const flat = flattenToDotNotation(nested);
// Result:
// {
//   'address.city': 'Los Angeles',
//   'address.zip': '90001',
//   'address.country': 'USA',
//   name: 'John Doe',
//   tags: ['customer', 'premium'],
//   createdAt: Date(2024-01-01)
// }

Update Functions

mergeDotNotationUpdate

Merges dot notation updates with existing data, handling both regular and dot notation keys.
function mergeDotNotationUpdate(
  existingData: Record<string, any>,
  updates: Record<string, any>
): Record<string, any>

Parameters

existingData
Record<string, any>
required
Current document data
updates
Record<string, any>
required
Updates to apply (may contain dot notation keys)

Returns

Record<string, any>
object
Merged data structure with updates applied

Behavior

  • Skips undefined values (Firestore doesn’t accept them)
  • Handles mixed regular and dot notation keys
  • Creates nested objects as needed
  • Preserves existing data not affected by updates

Example

import { mergeDotNotationUpdate } from '@spacelabstech/firestoreorm' // dotNotation';

const existing = {
  name: 'John Doe',
  address: {
    city: 'New York',
    zip: '10001',
    country: 'USA'
  },
  age: 30
};

const updates = {
  'address.city': 'Los Angeles',
  'address.zip': '90001',
  age: 31
};

const result = mergeDotNotationUpdate(existing, updates);
// Result:
// {
//   name: 'John Doe',
//   address: {
//     city: 'Los Angeles',
//     zip: '90001',
//     country: 'USA'
//   },
//   age: 31
// }

Validation Functions

validateDotNotationPath

Validates dot notation paths to prevent invalid field names.
function validateDotNotationPath(key: string): void

Parameters

key
string
required
The dot notation key to validate

Throws

Throws an Error if the key is invalid:
  • Empty or whitespace-only paths
  • Paths starting or ending with a dot
  • Paths with consecutive dots (empty parts)

Example

import { validateDotNotationPath } from '@spacelabstech/firestoreorm' // dotNotation';

// Valid paths
validateDotNotationPath('address.city');     // OK
validateDotNotationPath('user.profile.bio'); // OK
validateDotNotationPath('name');             // OK

// Invalid paths
validateDotNotationPath('');                 // Error: cannot be empty
validateDotNotationPath('.address.city');    // Error: cannot start with dot
validateDotNotationPath('address.city.');    // Error: cannot end with dot
validateDotNotationPath('address..city');    // Error: empty parts

Utility Functions

getRootFields

Extracts the root fields from an array of dot notation paths.
function getRootFields(keys: string[]): string[]

Parameters

keys
string[]
required
Array of keys (may include dot notation)

Returns

string[]
array
Array of unique root field names

Example

import { getRootFields } from '@spacelabstech/firestoreorm' // dotNotation';

const keys = [
  'address.city',
  'address.zip',
  'address.country',
  'name',
  'profile.bio',
  'profile.avatar'
];

const roots = getRootFields(keys);
// Result: ['address', 'name', 'profile']

getDotNotationDepth

Gets the depth of a dot notation path.
function getDotNotationDepth(key: string): number

Parameters

key
string
required
The dot notation key

Returns

number
number
The depth of the path (number of segments)

Example

import { getDotNotationDepth } from '@spacelabstech/firestoreorm' // dotNotation';

getDotNotationDepth('name');                    // 1
getDotNotationDepth('address.city');            // 2
getDotNotationDepth('user.profile.settings.theme'); // 4

Complete Usage Example

import {
  expandDotNotation,
  flattenToDotNotation,
  mergeDotNotationUpdate,
  validateDotNotationPath,
  getRootFields,
  getDotNotationDepth
} from '@spacelabstech/firestoreorm' // dotNotation';

// Updating nested fields with dot notation
const userUpdate = {
  'profile.bio': 'Software Engineer',
  'profile.social.twitter': '@johndoe',
  'settings.notifications.email': true
};

// Validate all paths
for (const key of Object.keys(userUpdate)) {
  validateDotNotationPath(key);
}

// Get affected root fields
const affectedFields = getRootFields(Object.keys(userUpdate));
console.log('Updating fields:', affectedFields);
// ['profile', 'settings']

// Expand to nested structure for local processing
const expanded = expandDotNotation(userUpdate);
console.log(expanded);
// {
//   profile: {
//     bio: 'Software Engineer',
//     social: { twitter: '@johndoe' }
//   },
//   settings: {
//     notifications: { email: true }
//   }
// }

// Merge with existing data
const existingUser = {
  name: 'John Doe',
  email: '[email protected]',
  profile: {
    bio: 'Developer',
    avatar: 'avatar.jpg'
  },
  settings: {
    theme: 'dark',
    notifications: {
      email: false,
      push: true
    }
  }
};

const mergedUser = mergeDotNotationUpdate(existingUser, userUpdate);
console.log(mergedUser);
// {
//   name: 'John Doe',
//   email: '[email protected]',
//   profile: {
//     bio: 'Software Engineer',
//     avatar: 'avatar.jpg',
//     social: { twitter: '@johndoe' }
//   },
//   settings: {
//     theme: 'dark',
//     notifications: {
//       email: true,
//       push: true
//     }
//   }
// }

// Flatten back to dot notation for Firestore
const flattened = flattenToDotNotation(mergedUser);
console.log(flattened);

Use Cases

Partial Updates Without Overwriting

// Without dot notation - overwrites entire address
await userRepo.update(userId, {
  address: { city: 'LA' }
});
// Result: { address: { city: 'LA' } } - zip and country are lost!

// With dot notation - updates only city
await userRepo.update(userId, {
  'address.city': 'LA'
});
// Result: { address: { city: 'LA', zip: '90001', country: 'USA' } }

Batch Updates on Nested Fields

const settingsUpdates = {
  'settings.theme': 'dark',
  'settings.language': 'en',
  'settings.notifications.email': true,
  'settings.notifications.sms': false
};

await userRepo.update(userId, settingsUpdates);

Working with Form Data

// Form fields using dot notation
const formData = {
  'profile.firstName': req.body.firstName,
  'profile.lastName': req.body.lastName,
  'profile.bio': req.body.bio,
  'settings.timezone': req.body.timezone
};

// Validate and update
for (const key of Object.keys(formData)) {
  validateDotNotationPath(key);
}

await userRepo.update(userId, formData);

Build docs developers (and LLMs) love