JSON Deep Compare with Field Validator
A powerful and flexible library for comparing JSON objects with support for deep comparison, regex validation, and customizable options.
Playground
Try before you implement! Test the library's capabilities and experiment with different comparison options using our interactive playground:
The playground allows you to:
- Compare JSON objects in real-time
- Customize comparison options
- Visualize match results and differences
- Test regex validations
Features
- Deep Comparison: Perform a deep comparison of JSON objects, including nested objects and arrays.
- Advanced Type Checking: Compare values with precise type detection, identifying specific data types (string, number, array, object, null, etc.) and providing detailed type mismatch information.
- Key and Value Type Comparison: Compare both keys and value types, ensuring that mismatches in types are reported.
- Regex Checks: Validate string values against regex patterns, with support for both exact path matching and key name matching.
- Result Structure: Get results in a structured format that clearly indicates matched keys and values, unmatched keys, unmatched values, and regex check results.
- Customizable Options: Customize the comparison behavior with options for ignoring specific keys, treating certain values as equivalent, and handling different data types.
- TypeScript Support: Full TypeScript type definitions included for better development experience.
- Performance Optimized: Designed to efficiently handle large JSON objects.
Installation
npm install json-deep-compare
You can also install from GitHub Packages. See Publishing Documentation for details.
Basic Usage
const JSONCompare = require('json-deep-compare');
// Create objects to compare
const obj1 = {
user: {
name: "Ashmeet Sehgal",
email: "ashmeet@ashmeetsehgal.com",
details: {
phone: "+91-9876543210"
}
},
products: [
{ id: "PROD-123", name: "Product 1" }
]
};
const obj2 = {
user: {
name: "Ashmeet Sehgal",
email: "contact@ashmeetsehgal.com", // Different email
details: {
phone: "+91-9876543210"
}
},
products: [
{ id: "PROD-123", name: "Product 1" }
]
};
// Create a comparator with regex checks
const comparator = new JSONCompare({
regexChecks: {
'email': /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
'phone': /\+\d{1,3}-\d{3,14}/, // Will match any key named 'phone'
'products[0].id': /^PROD-\d+$/
},
matchKeysByName: true // Enable matching by key name for regex checks
});
// Perform the comparison
const result = comparator.compareAndValidate(obj1, obj2);
console.log(result);
Options
You can customize the comparison behavior with the following options:
const options = {
// Keys to ignore during comparison
ignoredKeys: ['createdAt', 'updatedAt'],
// Values to treat as equivalent
equivalentValues: {
'booleanTypes': [true, 'true', 1],
'emptyValues': [null, undefined, '']
},
// Regex patterns for value validation
regexChecks: {
'email': /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
'user.details.phone': '\\+\\d{1,3}-\\d{3,14}', // String pattern
'products[0].id': /^PROD-\d+$/
},
// Whether to strictly compare types
strictTypes: true,
// Whether to ignore keys in obj2 that aren't in obj1
ignoreExtraKeys: false,
// Whether to match regex by key name instead of only by path
matchKeysByName: true
};
const comparator = new JSONCompare(options);
Result Structure
The comparison result has the following structure:
{
matched: {
keys: [], // Matched keys
values: [] // Matched values
},
unmatched: {
keys: [], // Keys found in one object but not the other
values: [], // Values that don't match
types: [] // Values with mismatched types
},
regexChecks: {
passed: [], // Values that passed regex validation
failed: [] // Values that failed regex validation
},
summary: {
matchPercentage: 0, // Percentage of matched elements
totalKeysCompared: 0, // Total number of keys compared
totalMatched: 0, // Total number of matched elements
totalUnmatched: 0, // Total number of unmatched elements
totalRegexChecks: 0 // Total number of regex checks performed
}
}
Advanced Usage
Matching by Key Name
With the matchKeysByName
option set to true
, the library will apply regex checks to all keys with matching names, not just exact paths. This is useful for validating all fields of a specific type regardless of their location in the object.
const comparator = new JSONCompare({
regexChecks: {
'email': /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
},
matchKeysByName: true
});
// This will validate both user.email and customer.email fields
Treating Values as Equivalent
You can define sets of values that should be treated as equivalent:
const comparator = new JSONCompare({
equivalentValues: {
'booleanTypes': [true, 'true', 1],
'emptyValues': [null, undefined, '']
}
});
// true, 'true', and 1 will be considered equivalent
// null, undefined, and '' will be considered equivalent
Ignoring Extra Keys
If you only care about whether obj2 contains all the keys from obj1, you can ignore extra keys:
const comparator = new JSONCompare({
ignoreExtraKeys: true
});
// Keys in obj2 that aren't in obj1 will be ignored
Type Checking
The library includes advanced type checking capabilities to identify and report the specific types of values being compared.
Supported Types
The following types are precisely detected:
- Primitive types:
string
,number
,boolean
,undefined
- Complex types:
array
,object
,null
- Special objects:
date
,regex
- Custom object types based on constructor name
Type Checking Example
const JSONCompare = require('json-deep-compare');
const obj1 = {
id: 1, // Number
name: "Product", // String
price: "19.99" // String (will be compared with a number)
};
const obj2 = {
id: "1", // String (type mismatch with obj1.id)
name: "Product", // String (matching)
price: 19.99 // Number (type mismatch with obj1.price)
};
// Create a JSONCompare instance
const compare = new JSONCompare({
strictTypes: false // Set to true to fail comparison on type mismatches
});
// Perform the comparison
const result = compare.compare(obj1, obj2);
// Check for type mismatches
if (result.unmatched.types.length > 0) {
console.log("Type mismatches found:");
result.unmatched.types.forEach(mismatch => {
console.log(`Path: ${mismatch.path}`);
console.log(`Expected type: ${mismatch.expected}, Actual type: ${mismatch.actual}`);
});
}
Strict Type Checking
When strictTypes
is set to true
, the comparison will stop at the first type mismatch for each path:
const strictCompare = new JSONCompare({ strictTypes: true });
const strictResult = strictCompare.compare(obj1, obj2);
Type Information in Results
Type information is included in both matched and unmatched values:
// For matched values
{
path: "name",
value: "Product",
type: "string"
}
// For unmatched values
{
path: "id",
expected: 1,
actual: "1",
expectedType: "number",
actualType: "string",
message: "Values do not match"
}
// For type mismatches
{
path: "id",
expected: "number",
actual: "string",
message: "Types do not match: expected 'number', got 'string'"
}
Type-Safe Equivalence
When using equivalence rules with different types, the types are still reported correctly:
const compare = new JSONCompare({
equivalentValues: {
'nullish': [null, undefined]
}
});
// Result will show:
// "Values considered equivalent by rule 'nullish'"
// but will still report type1: "null", type2: "undefined"
License
MIT
Support This Project
If you find this library useful for your projects, please consider supporting its development and maintenance:
- ⭐ Star the project on GitHub - It helps increase visibility
Your support helps keep this project maintained and improved with new features!