Onyx Database Relationships
One-to-Many Relationship Tutorial
Build one-to-many relationships in both the open source ORM and the cloud-native resolver experience. Toggle between versions to see how to save a Sailboat
and its CrewMember
roster.
Select Onyx Open Source or Onyx Cloud to tailor the instructions to your environment.
Onyx Open Source Tutorial
Switch to Onyx Open Source to review the annotation-driven implementation and sample code.
Onyx Cloud Tutorial
Model the one-to-many relationship with resolver attributes and cascade saves using graph paths so each crew member references the correct sailboat.
1
Capture resolver schema changes
Define resolver-backed attributes for
crew
and sailboat
in your schema JSON. Each resolver performs a filtered query to retrieve related records.1{
2 "tables": [
3 {
4 "name": "Sailboat",
5 "identifier": {
6 "name": "registrationCode",
7 "type": "String",
8 "generator": "None"
9 },
10 "partition": "",
11 "attributes": [
12 { "name": "registrationCode", "type": "String" },
13 { "name": "name", "type": "String" }
14 ],
15 "resolvers": [
16 {
17 "name": "crew",
18 "resolver": "return await db.from('CrewMember').where(eq('sailboatId', this.registrationCode)).list();"
19 }
20 ],
21 "indexes": []
22 },
23 {
24 "name": "CrewMember",
25 "identifier": {
26 "name": "id",
27 "type": "String",
28 "generator": "None"
29 },
30 "partition": "",
31 "attributes": [
32 { "name": "id", "type": "String" },
33 { "name": "firstName", "type": "String" },
34 { "name": "lastName", "type": "String" },
35 { "name": "sailboatId", "type": "String" }
36 ],
37 "resolvers": [
38 {
39 "name": "sailboat",
40 "resolver": "return await db.from('Sailboat').where(eq('registrationCode', this.sailboatId)).firstOrNull();"
41 }
42 ],
43 "indexes": []
44 }
45 ],
46 "revisionDescription": "Resolver-based one-to-many relationship"
47}
2
Shape the object graph
Create the sailboat payload and embed crew members with stable identifiers so subsequent saves update the same records.
1const sailboat = {
2 registrationCode: "NCC1701",
3 name: "Wind Passer",
4 crew: [
5 {
6 id: "crew_001",
7 firstName: "Martha",
8 lastName: "McFly"
9 },
10 {
11 id: "crew_002",
12 firstName: "Emmett",
13 lastName: "Brown"
14 }
15 ]
16};
3
Cascade the save
Use
db.cascade()
with crew:CrewMember(sailboatId, registrationCode)
to ensure the SDK assignssailboatId
for each crew member during persistence.1await db
2 .cascade("crew:CrewMember(sailboatId, registrationCode)")
3 .save("Sailboat", sailboat);
4
5console.log("Saved " + sailboat.crew.length + " crew members with " + sailboat.name);
4
Resolve the crew
Query the sailboat and resolve the
crew
resolver to confirm the cascade save produced the expected child records.1const savedSailboat = await db
2 .from("Sailboat")
3 .where(eq("registrationCode", "NCC1701"))
4 .resolve("crew")
5 .firstOrNull();
6
7console.log("Crew count: " + (savedSailboat?.crew?.length ?? 0));