Skip to main content
Version: v7 / v8

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."

https://example.com

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 labels
  • MatchMode[] - 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:

ModeTypeDescriptionRequires threshold
allUnaryEvery item in the array matches the subqueryNo
someUnaryAt least one item in the array matches the subqueryNo
noneUnaryNo items in the array match the subqueryNo
atLeastThresholdAt least N items match the subqueryYes
atMostThresholdAt most N items match the subqueryYes
exactlyThresholdExactly N items match the subqueryYes

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' },
],
},
},
],
};
info

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 levelFormats
Full"jsonlogic"1, "jsonata", "cel", "spel", "natural_language", "mongodb", "mongodb_query"
Partial2"sql", "parameterized", "drizzle"
None"parameterized_named"3, "prisma", "sequelize", "elasticsearch", "ldap"
caution

In unsupported formats, rules with valid match properties are treated as invalid and ignored during export.

Footnotes

  1. JsonLogic was the original inspiration for this feature.

  2. SQL-based formats only support primitive value arrays when preset is "postgresql". Other RDBMS platforms lack support for nested tables or have overly complex implementations.

  3. PostgreSQL does not support named parameters