Describe the bug
When using a collection with syncMode: 'on-demand' in a subquery, the filters from the subquery's .where() clauses are not passed to the collection's queryFn via ctx.meta?.loadSubsetOptions. This prevents query-driven sync from working when collections are used in subqueries, forcing the API to load all data instead of filtered subsets.
To Reproduce
Steps to reproduce the behavior:
- Create a collection with
syncMode: 'on-demand' and a queryFn that uses parseLoadSubsetOptions:
const ordersCollection = createCollection(
queryCollectionOptions({
syncMode: 'on-demand',
queryKey: ['orders'],
queryFn: async ctx => {
const { filters, sorts, limit } = parseLoadSubsetOptions(ctx.meta?.loadSubsetOptions);
console.log('Filters:', filters); // Empty array when used in subquery
console.log('loadSubsetOptions.where:', ctx.meta?.loadSubsetOptions?.where); // undefined
const params = {};
filters.forEach(({ field, operator, value }) => {
// Map filters to API params - never executes when in subquery
});
return api.listOrders(params);
},
})
);
- Use the collection in a subquery with filters:
const query = q => {
const prepaidOrder = q
.from({ prepaidOrder: ordersCollection })
.where(({ prepaidOrder }) => gte(prepaidOrder.scheduled_at, today))
.where(({ prepaidOrder }) => eq(prepaidOrder.status, 'queued'))
.orderBy(({ prepaidOrder }) => prepaidOrder.scheduled_at, 'asc');
return q
.from({ charge: chargesCollection })
.fullJoin({ prepaidOrder }, ({ charge, prepaidOrder }) =>
eq(charge?.address_id, prepaidOrder?.address_id)
);
};
- Observe that
ctx.meta?.loadSubsetOptions.where is undefined and filters is an empty array []
Expected behavior
When a collection is used in a subquery with .where() clauses, those filters should be extracted and passed to the collection's queryFn via ctx.meta?.loadSubsetOptions.where, allowing the API to be called with the correct filter parameters. This should work the same way as when the collection is queried directly.
Actual behavior
ctx.meta?.loadSubsetOptions.where is undefined
ctx.meta?.loadSubsetOptions.orderBy is undefined
parseLoadSubsetOptions() returns empty arrays for filters and sorts
- Only
ctx.meta?.loadSubsetOptions.subscription is present (a CollectionSubscription instance)
- The
queryFn cannot determine what filters to apply, so it either loads all data or applies incorrect defaults
Code Example
import { createCollection, parseLoadSubsetOptions } from '@tanstack/react-db';
import { queryCollectionOptions } from '@tanstack/query-db-collection';
import { gte, eq } from '@tanstack/react-db';
// Collection with on-demand sync
const ordersCollection = createCollection(
queryCollectionOptions({
syncMode: 'on-demand',
queryKey: ['orders'],
getKey: (item) => item.id,
queryFn: async ctx => {
const { filters, sorts, limit } = parseLoadSubsetOptions(ctx.meta?.loadSubsetOptions);
// ❌ PROBLEM: When used in subquery, these are all empty/undefined
// filters: []
// sorts: []
// ctx.meta?.loadSubsetOptions.where: undefined
const params = {};
filters.forEach(({ field, operator, value }) => {
// This never runs when collection is in subquery
if (operator === 'gte' && field[field.length - 1] === 'scheduled_at') {
params.scheduled_at_min = value;
}
if (operator === 'eq' && field[field.length - 1] === 'status') {
params.status = value;
}
});
return api.listOrders(params); // Called without filters
},
})
);
// Direct query - WORKS ✅
const directQuery = q =>
q
.from({ order: ordersCollection })
.where(({ order }) => gte(order.scheduled_at, today))
.where(({ order }) => eq(order.status, 'queued'));
// ✅ Filters are passed to queryFn correctly
// Subquery - DOESN'T WORK ❌
const subqueryExample = q => {
const prepaidOrder = q
.from({ prepaidOrder: ordersCollection })
.where(({ prepaidOrder }) => gte(prepaidOrder.scheduled_at, today))
.where(({ prepaidOrder }) => eq(prepaidOrder.status, 'queued'));
return q
.from({ charge: chargesCollection })
.fullJoin({ prepaidOrder }, ({ charge, prepaidOrder }) =>
eq(charge?.address_id, prepaidOrder?.address_id)
);
};
// ❌ Filters are NOT passed to queryFn
Additional context
- Version:
@tanstack/react-db@0.5.11, @tanstack/query-db-collection@1.0.6
- Impact: This prevents efficient query-driven sync for collections used in complex queries with joins, forcing full dataset loads and client-side filtering
- Workaround: Currently loading all data and filtering client-side, which defeats the purpose of on-demand sync for large datasets
- The
subscription object is available in ctx.meta?.loadSubsetOptions.subscription but doesn't expose the where expression that could be used to extract filters
Related:
This is related to query-driven sync feature introduced in v0.5. The documentation shows it working for direct queries, but doesn't mention this limitation with subqueries.
Describe the bug
When using a collection with
syncMode: 'on-demand'in a subquery, the filters from the subquery's.where()clauses are not passed to the collection'squeryFnviactx.meta?.loadSubsetOptions. This prevents query-driven sync from working when collections are used in subqueries, forcing the API to load all data instead of filtered subsets.To Reproduce
Steps to reproduce the behavior:
syncMode: 'on-demand'and aqueryFnthat usesparseLoadSubsetOptions:ctx.meta?.loadSubsetOptions.whereisundefinedandfiltersis an empty array[]Expected behavior
When a collection is used in a subquery with
.where()clauses, those filters should be extracted and passed to the collection'squeryFnviactx.meta?.loadSubsetOptions.where, allowing the API to be called with the correct filter parameters. This should work the same way as when the collection is queried directly.Actual behavior
ctx.meta?.loadSubsetOptions.whereisundefinedctx.meta?.loadSubsetOptions.orderByisundefinedparseLoadSubsetOptions()returns empty arrays forfiltersandsortsctx.meta?.loadSubsetOptions.subscriptionis present (aCollectionSubscriptioninstance)queryFncannot determine what filters to apply, so it either loads all data or applies incorrect defaultsCode Example
Additional context
@tanstack/react-db@0.5.11,@tanstack/query-db-collection@1.0.6subscriptionobject is available inctx.meta?.loadSubsetOptions.subscriptionbut doesn't expose the where expression that could be used to extract filtersRelated:
This is related to query-driven sync feature introduced in v0.5. The documentation shows it working for direct queries, but doesn't mention this limitation with subqueries.