Subqueries and nested data
Modern applications frequently handle complex, nested data structures such as object arrays or hierarchical JSON. React Query Builder's subquery feature enables sophisticated queries against these nested structures through intuitive match modes like "all," "some," or "none."
Configuring subqueries
Enable subqueries for a field by adding a matchModes
property to its field definition. This property determines available match modes and their labels. You can also control subquery behavior globally using the getMatchModes
and getSubQueryBuilderProps
props.
Match modes configuration
The matchModes
property accepts several formats:
true
- Enables all available match modes with default labelsMatchMode[]
- Array of match mode names (e.g.,['all', 'some', 'none']
)Option<MatchMode>[]
- Array of objects with custom labels (e.g.,[{ name: 'all', label: 'Every' }]
)
const fields: Field[] = [
{
name: 'nestedStringArray',
label: 'Nested String Array',
// Enable all match modes with default labels
matchModes: true,
},
{
name: 'nestedNumberArray',
label: 'Nested Number Array',
// Enable specific match modes with custom labels
matchModes: [
{ name: 'all', label: 'Every' },
{ name: 'none', label: 'Not one' },
{ name: 'some', label: 'Several' },
],
},
{
name: 'nestedObjectArray',
label: 'Nested Object Array',
// Enable specific match modes with default labels
matchModes: ['all', 'none', 'some'],
// Define properties of objects in the nested array
subproperties: [
{ name: 'firstName', label: 'First Name' },
{ name: 'lastName', label: 'Last Name' },
],
},
];
Dynamic match mode configuration
Configure match modes dynamically using the getMatchModes
prop at the query builder level. This function executes for each field, enabling conditional match mode configuration based on field properties:
const getMatchModes = (field: string, misc: { fieldData: Field }) => {
// Return true to enable all match modes for any field
if (field === 'flexibleArray') return true;
// Return specific match modes based on field type
if (misc.fieldData.datatype === 'array') {
return ['all', 'some', 'none'];
}
// Return false or undefined to disable subqueries for this field
return false;
};
<QueryBuilder
fields={fields}
getMatchModes={getMatchModes}
// ... other props
/>
Customizing subquery builder props
The getSubQueryBuilderProps
prop customizes individual subquery builder configurations. Use this to provide different field sets, operators, or other settings for nested queries:
const getSubQueryBuilderProps = (field: string, misc: { fieldData: Field }) => {
// Return props that should override the parent query builder's configuration
if (field === 'nestedObjectArray') {
return {
fields: misc.fieldData.subproperties || [],
operators: [
{ name: '=', label: 'equals' },
{ name: 'contains', label: 'contains' },
{ name: 'beginsWith', label: 'begins with' },
],
// Disable certain features for subqueries
showCloneButtons: false,
showLockButtons: false,
};
}
// For primitive arrays, don't show field selector
if (field === 'nestedStringArray') {
return {
fields: [{ name: '', label: '' }],
autoSelectField: true,
};
}
return {};
};
<QueryBuilder
fields={fields}
getSubQueryBuilderProps={getSubQueryBuilderProps}
// ... other props
/>
Note: Props like query
, onQueryChange
, and enableDragAndDrop
are automatically managed and cannot be overridden for subquery builders.
Available match modes
React Query Builder supports six match modes:
Mode | Type | Description | Requires threshold |
---|---|---|---|
all | Unary | Every item in the array matches the subquery | No |
some | Unary | At least one item in the array matches the subquery | No |
none | Unary | No items in the array match the subquery | No |
atLeast | Threshold | At least N items match the subquery | Yes |
atMost | Threshold | At most N items match the subquery | Yes |
exactly | Threshold | Exactly N items match the subquery | Yes |
Working with object properties
For object arrays (not primitive arrays), use the subproperties
configuration to specify which object properties are available in subqueries. This functions identically to the main fields
prop.
When subproperties
is undefined, subquery rules don't render a field selector, and the field
property should remain an empty string.
Query structure
Subqueries store as nested RuleGroupType
objects in the rule's value
property. The match
property contains the mode and optional threshold:
const exampleQuery: RuleGroupType = {
combinator: 'and',
rules: [
{
field: 'nestedStringArray',
operator: '=', // Ignored when match is present
match: { mode: 'atMost', threshold: 2 },
value: {
combinator: 'and',
rules: [{ field: '', operator: 'contains', value: 'abc' }],
},
},
{
field: 'nestedObjectArray',
operator: '=',
match: { mode: 'all' },
value: {
combinator: 'and',
rules: [
{ field: 'firstName', operator: 'beginsWith', value: 'S' },
{ field: 'lastName', operator: 'doesNotEndWith', value: 's' },
],
},
},
],
};
When a rule has a valid match
property, the operator
property is ignored. The match mode determines subquery evaluation logic.
Export format support
Export format support for subqueries varies by implementation:
Support level | Formats |
---|---|
Full | "jsonlogic"1, "jsonata", "cel", "spel", "natural_language", |
Partial2 | "sql", "parameterized", "drizzle" |
None | "parameterized_named"3, "prisma", "sequelize", "elasticsearch", "ldap" |
In unsupported formats, rules with valid match
properties are treated as invalid and ignored during export.