Ignore Timestamp Keys with Lodash isEqualWith
Deep equality checks in JavaScript frequently fail when comparing
objects containing dynamic runtime data such as createdAt
or updatedAt properties. The Lodash library solves this
problem through _.isEqualWith, an extension of
_.isEqual that accepts a customizer callback.
This article explains how to write a customizer function that
conditionally ignores specified timestamp keys, bypassing value checks
on those dynamic fields while preserving standard deep-comparison logic
for the remainder of the data structures.
The Customizer Function Signature
The _.isEqualWith method iterates through values and
delegates comparison logic to the customizer whenever one is
supplied:
_.isEqualWith(value, other, [customizer])The customizer function receives several arguments on each step:
customizer(objValue, othValue, key, object, other, stack)
objValue: The current value from the first object.othValue: The current value from the second object.key: The property name or array index currently being evaluated.object: The parent object ofobjValue.other: The parent object ofothValue.stack: Internal tracks for handling circular references.
Return Values
The customizer relies on specific return values to determine equality:
true: Instructs Lodash to treat the comparison as equal, stopping further traversal on that property.false: Instructs Lodash to treat the comparison as unequal immediately.undefined: Instructs Lodash to fall back to its internal deep-comparison algorithm for that property.
Implementing the Timestamp Bypass
To bypass specific timestamp keys, check if the current
key matches your target dynamic properties. If it matches,
return true. Otherwise, return undefined to
let Lodash proceed with normal comparison.
const _ = require('lodash');
const IGNORED_TIMESTAMP_KEYS = new Set([
'createdAt',
'updatedAt',
'timestamp',
'lastModified'
]);
function ignoreTimestampsCustomizer(objValue, othValue, key) {
if (IGNORED_TIMESTAMP_KEYS.has(key)) {
return true;
}
return undefined;
}Practical Example
Consider two objects representing database entities with identical business data but divergent timestamp values:
const recordA = {
id: 101,
user: {
name: 'Jane Doe',
role: 'Admin'
},
createdAt: '2023-01-15T08:30:00.000Z',
updatedAt: '2023-01-15T08:30:00.000Z'
};
const recordB = {
id: 101,
user: {
name: 'Jane Doe',
role: 'Admin'
},
createdAt: '2023-01-15T08:30:00.000Z',
updatedAt: '2023-08-20T14:45:12.000Z' // Divergent timestamp
};
// Standard comparison returns false
console.log(_.isEqual(recordA, recordB));
// Output: false
// Customizer comparison returns true
const isEqual = _.isEqualWith(recordA, recordB, ignoreTimestampsCustomizer);
console.log(isEqual);
// Output: trueAdding Value Validation
If you want to ensure the ignored keys are actually valid timestamps rather than arbitrary data or missing properties, add a conditional format check inside the customizer:
function isIsoDateString(val) {
return typeof val === 'string' && !isNaN(Date.parse(val));
}
function validatedTimestampCustomizer(objValue, othValue, key) {
if (IGNORED_TIMESTAMP_KEYS.has(key)) {
// Only ignore if both properties are valid date representations
if (isIsoDateString(objValue) && isIsoDateString(othValue)) {
return true;
}
}
return undefined;
}This ensures that if a key like updatedAt is corrupted
(for example, containing null in one object and a valid
string in another), the comparison will correctly report the
mismatch.