Include Syntax
include is the parameter that tells SemiLayer which relations to attach
to each parent row. Same shape on every read op: query, search,
similar, feed, and their streaming variants.
Two forms
Shorthand — true
Use relation defaults: all declared fields, no extra filter, defaultIncludeLimit rows.
Object — per-call overrides
Customize any of the four knobs:
Mix forms freely — one relation can be shorthand, another fully customized.
The four knobs
where
Same operator vocabulary as query predicates:
$eq, $in, $gt, $gte, $lt, $lte. Top-level keys AND together.
The foreign key filter (recipe_id IN (...)) is added automatically by
the planner — you don't write it.
select
Project specific fields. Smaller payload over the wire, slightly cheaper
compute. Defaults to all fields on the lens ('*'). Selected fields
must be declared on the target lens or you get a 422.
orderBy
Single rule or array (applied in order). Used for the per-parent slice — "top 3 reviews by helpful_count" means sort per recipe, take the first 3.
limit
Per-parent cap. The planner caps this at 1000; the relation's
defaultIncludeLimit applies when the caller omits it.
Across the read ops
Same include spec, four places it shows up:
query
Relations land directly on each row:
search / similar
Relations land on metadata:
feed
Same place as search — on each item's metadata:
Streaming
stream.query and stream.search both accept include. Relations
are attached per-row before the row yields — you never see a row
without its relations:
subscribe() and observe() do not support include — those
stream single records as they change. If you need joined data there,
re-fetch via query({ where: { id: event.recordId }, include }) on each
event.
CLI
The --include flag takes JSON — same shape as the parameter.
Partial failures
When one relation fails (access denied, bridge down, missing capability),
the primary rows still land. The failed relation returns empty on those
rows, and meta.includeErrors names it:
Failure reasons: unknown_relation, access_denied,
capabilities.batchRead, source_query_failed, source_unreachable,
query_timeout. See Access Rules and
Bridges Without Support for the
causes.
What include doesn't do
- Nested includes — you can't
include: { reviews: { include: { author: true } } }. Include is one level deep in v1. For depth, chain calls. - Parent-side filters on child values — "recipes with any 5-star review" can't be expressed in
include. Do aqueryon the child lens first, thenwhere: { id: { $in: ids } }on the parent. - Aggregates —
avg(rating),count(reviews), etc. Aggregations are a separate primitive, not a flavour ofinclude. - Subscribe / observe — see above.
Next: Cross-source joins.