Parent Options
The parent and parentProperty options allow you to specify parent context when executing JSONPath queries. This is particularly useful for nested query scenarios where you need to maintain a reference to the containing object or array.
Table of Contents
Overview
When working with nested data structures, you often need to query a subset of data while maintaining context about where that data lives in the larger structure. The parent options enable this by allowing you to pass:
- parent: The parent object or array containing the data being queried
- parentProperty: The property name (string) or array index (number) in the parent that contains this data
This information can be used by:
- Filter expressions that need to reference parent data (e.g., using the
^parent selector) - Debugging tools to understand data relationships
- Custom result processors that need context
Options
parent
Type: unknown
The parent object or array that contains the data being queried.
interface QueryOptions {
parent?: unknown;
}2
3
parentProperty
Type: string | number
The property name (for objects) or array index (for arrays) in the parent that contains the queried data.
interface QueryOptions {
parentProperty?: string | number;
}2
3
Usage
Basic Usage
import { JSONPath } from '@jsonpathx/jsonpathx';
const parent = {
items: [
{ id: 1, name: 'Item 1', price: 10 },
{ id: 2, name: 'Item 2', price: 20 },
],
metadata: {
currency: 'USD',
total: 2,
},
};
// Query items with parent context
const prices = await JSONPath.query(
'$[*].price',
parent.items,
{
parent,
parentProperty: 'items',
}
);
console.log(prices); // [10, 20]2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
QueryBuilder API
The QueryBuilder provides a fluent withParent() method for setting parent context:
const results = await JSONPath.create(parent.items)
.withParent(parent, 'items')
.query('$[*].price')
.filter((price) => price >= 15)
.execute();
console.log(results); // [20]2
3
4
5
6
7
withParent() Method
withParent(parent: unknown, property?: string | number): thisParameters:
parent: The parent object or arrayproperty(optional): The property name or array index
Returns: The builder instance for chaining
Example without property:
const results = await JSONPath.create(data)
.withParent(parentObject)
.query('$[*].id')
.execute();2
3
4
Array Parent with Index
When the parent is an array, use a numeric index as the parentProperty:
const categories = [
{
id: 'electronics',
products: [
{ name: 'TV', price: 500 },
{ name: 'Radio', price: 50 },
],
},
];
const firstCategory = categories[0];
const products = await JSONPath.query(
'$[*].name',
firstCategory.products,
{
parent: categories,
parentProperty: 0, // Array index
}
);
console.log(products); // ['TV', 'Radio']2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Use Cases
1. API Responses with Metadata
When working with paginated API responses:
const apiResponse = {
data: [
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' },
],
pagination: {
page: 1,
total: 100,
},
};
const userNames = await JSONPath.query(
'$[*].name',
apiResponse.data,
{
parent: apiResponse,
parentProperty: 'data',
}
);
// Parent context maintained for reference
console.log('Page:', apiResponse.pagination.page);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2. Nested Configurations
Querying configuration hierarchies:
const config = {
database: {
connections: [
{ host: 'localhost', port: 5432 },
{ host: 'replica1', port: 5432 },
],
poolSize: 10,
},
};
const hosts = await JSONPath.create(config.database.connections)
.withParent(config.database, 'connections')
.query('$[*].host')
.execute();2
3
4
5
6
7
8
9
10
11
12
13
14
3. E-commerce Product Catalogs
Managing product categories:
const catalog = {
categories: [
{
id: 'laptops',
products: [
{ name: 'Pro Laptop', price: 1299, inStock: true },
{ name: 'Gaming Laptop', price: 1899, inStock: false },
],
},
],
};
const laptopCategory = catalog.categories[0];
const inStockPrices = await JSONPath.create(laptopCategory.products)
.withParent(laptopCategory, 'products')
.query('$[*]')
.filter((product) => product.inStock)
.map((product) => product.price)
.execute();2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
4. Multi-level Nested Structures
Complex hierarchies like warehouses:
const warehouse = {
location: 'New York',
departments: [
{
name: 'Electronics',
shelves: [
{
id: 'A1',
items: [
{ sku: '001', quantity: 10 },
{ sku: '002', quantity: 5 },
],
},
],
},
],
};
const department = warehouse.departments[0];
const shelf = department.shelves[0];
const skus = await JSONPath.create(shelf.items)
.withParent(shelf, 'items')
.query('$[*].sku')
.execute();2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Integration with Other Features
With Result Types
Parent options work seamlessly with different result types:
const data = {
items: [{ id: 1 }, { id: 2 }],
};
// Get paths
const paths = await JSONPath.query('$[*].id', data.items, {
parent: data,
parentProperty: 'items',
resultType: 'path',
});
// ['$[0].id', '$[1].id']
// Get pointers
const pointers = await JSONPath.query('$[*].id', data.items, {
parent: data,
parentProperty: 'items',
resultType: 'pointer',
});
// ['/0/id', '/1/id']2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
With Flatten Option
Combine with array flattening:
const data = {
items: [
{ tags: ['a', 'b'] },
{ tags: ['c', 'd'] },
],
};
const allTags = await JSONPath.query('$[*].tags', data.items, {
parent: data,
parentProperty: 'items',
flatten: true,
});
// ['a', 'b', 'c', 'd']2
3
4
5
6
7
8
9
10
11
12
13
With Caching
Parent options are included in cache key generation:
JSONPath.enableCache();
const result1 = await JSONPath.query('$[*].id', data.items, {
parent: data,
parentProperty: 'items',
enableCache: true,
});
// Subsequent queries with same parameters use cache
const result2 = await JSONPath.query('$[*].id', data.items, {
parent: data,
parentProperty: 'items',
enableCache: true,
});2
3
4
5
6
7
8
9
10
11
12
13
14
With Callbacks
Access parent context in callbacks:
await JSONPath.query('$[*].price', data.items, {
parent: data,
parentProperty: 'items',
callback: (value, type, path) => {
console.log(`Found ${value} at ${path}`);
// Parent context available in closure
console.log(`Parent has ${data.items.length} items`);
},
});2
3
4
5
6
7
8
9
API Reference
QueryOptions Interface
interface QueryOptions {
/**
* Optional parent object context
* Used when query is executed in a nested context
*/
parent?: unknown;
/**
* Optional parent property name/index
* The property name or array index in the parent that contains this data
*/
parentProperty?: string | number;
// ... other options
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
JSONPath.query()
static async query<T = unknown>(
path: string,
data: unknown,
options?: QueryOptions
): Promise<T[]>2
3
4
5
Parameters:
path: JSONPath expression to evaluatedata: The data to queryoptions: Query options includingparentandparentProperty
Returns: Array of query results
Example:
const results = await JSONPath.query('$[*].id', data, {
parent: parentObject,
parentProperty: 'items',
});2
3
4
QueryBuilder.withParent()
withParent(parent: unknown, property?: string | number): thisParameters:
parent: The parent object or array containing the queried dataproperty(optional): Property name or array index in the parent
Returns: The builder instance for method chaining
Example:
const builder = JSONPath.create(data)
.withParent(parent, 'items')
.query('$[*].id');
const results = await builder.execute();2
3
4
5
Edge Cases
Null Parent
You can pass null as the parent if needed:
const results = await JSONPath.query('$[*].id', data, {
parent: null,
parentProperty: 'items',
});2
3
4
Zero as Index
Zero is a valid array index:
const parent = [data];
const results = await JSONPath.query('$.id', data, {
parent,
parentProperty: 0,
});2
3
4
5
Empty String Property
Empty strings are valid property names in JavaScript:
const parent = { '': data };
const results = await JSONPath.query('$[*].id', data, {
parent,
parentProperty: '',
});2
3
4
5
Parent Without Property
You can specify just the parent without the property:
const results = await JSONPath.query('$[*].id', data, {
parent: parentObject,
});2
3
Property Without Parent
You can specify just the property name without the parent:
const results = await JSONPath.query('$[*].id', data, {
parentProperty: 'items',
});2
3
Best Practices
Use with QueryBuilder: The fluent API makes parent context more readable
typescript// Good const results = await JSONPath.create(data) .withParent(parent, 'items') .query('$[*].id') .execute();1
2
3
4
5Document Context: When using parent options, add comments explaining the hierarchy
typescript// Query products within the laptop category const prices = await JSONPath.query('$[*].price', laptopCategory.products, { parent: laptopCategory, parentProperty: 'products', });1
2
3
4
5Consistent Naming: Use consistent variable names for parent relationships
typescriptconst category = catalog.categories[0]; const products = category.products; const results = await JSONPath.query('$[*]', products, { parent: category, parentProperty: 'products', });1
2
3
4
5
6
7Type Safety: Use TypeScript to ensure correct parent/property relationships
typescriptinterface Category { products: Product[]; } const category: Category = ...; const results = await JSONPath.query('$[*]', category.products, { parent: category, parentProperty: 'products', // Type-safe property name });1
2
3
4
5
6
7
8
9