Onyx Cloud Relationships

Relationship Resolvers

Relationship resolvers hydrate related records on demand without embedding full entity definitions. They are perfect for joining data across tables, shaping dashboards, and keeping write operations lightweight.

Resolvers are exclusive to Onyx Cloud Database. They support cascading writes, projections, predicates, and explicit resolution in your scripts and Admin Console dashboards.

1

Declare the resolver in your schema

Create a resolver-backed relationship in the schema designer. Choose Resolver as the relationship type, point to the target entity, and provide the join fields (for example, Actor(movieId, id) to connect a movie to its actors).

After you publish the revision, the resolver behaves like any other relationship and can be referenced from scripts, dashboards, and query APIs.

Resolver relationships are read-only views over the target entity. Use cascade helpers when you need to persist related data alongside the parent record.

2

Cascade saves through a resolver

Use the cascade helper to persist a parent entity and its resolver-backed children in a single operation. The resolver path (actors:Actor(movieId, id) in this example) ensures the related actors are stored using the correct join fields.

1// Define the Movie entity with related Actors
2const movieWithActors = {
3  id: 'movie_001',
4  title: 'Inception',
5  releaseYear: 2010,
6  genre: 'Sci-Fi',
7  actors: [
8    { id: 'actor_001', name: 'Leonardo DiCaprio', role: 'Cobb' },
9    { id: 'actor_002', name: 'Marion Cotillard', role: 'Mal' },
10    { id: 'actor_003', name: 'Tom Hardy', role: 'Eames' }
11  ]
12};
13
14// Persist the movie and the related actors in one call
15await db.cascade('actors:Actor(movieId, id)').save('Movie', movieWithActors);
16
17// Verify by resolving the actors relationship after the save
18const savedMovie = await db
19  .from('Movie')
20  .resolve('actors')
21  .where(eq('id', 'movie_001'))
22  .firstOrNull();
23
24db.results = savedMovie;

Cascading through a resolver is ideal for onboarding or synchronization scripts where the payload already contains nested collections.

3

Query against resolver fields

Resolvers can be projected, filtered, and eagerly fetched just like native relationships. Include them in selectFields, reference nested metadata inside where clauses, or call resolve to hydrate the related documents only when you need them.

1// Select a resolver in the projection
2const contractsWithBars = await db
3  .from('Contract')
4  .selectFields('ticker', 'symbol', 'type', 'relatedBars')
5  .limit(5)
6  .list();
7
8// Filter using a resolver property in a predicate
9const contractsByBarCondition = await db
10  .from('Contract')
11  .where(gt('relatedBars.size', 0))
12  .selectFields('ticker', 'symbol', 'relatedBars')
13  .limit(5)
14  .list();
15
16// Explicitly resolve the relationship to hydrate the related data
17const contractsResolved = await db
18  .from('Contract')
19  .resolve('relatedBars')
20  .limit(3)
21  .list();
22
23db.results = {
24  contractsWithBars: contractsWithBars.records,
25  contractsByBarCondition: contractsByBarCondition.records,
26  contractsResolved: contractsResolved.records
27};

Resolver properties expose helper metrics such as size, letting you build predicates without loading every related record.

Need Help?

If you have any questions or need assistance: