Updating an Attribute Within Your Model
This tutorial demonstrates how to update your data model in Onyx Database, including adding, removing, and changing attributes. You will learn how the database handles lightweight migrations when your model changes.
Steps to Update Your Model (Onyx Cloud Database)
1
Declare the Entities
Use the provided JSON schema to declare your entities and deploy the database using this schema definition.
1{
2 "tables": [
3 {
4 "name": "Account",
5 "identifier": {
6 "name": "accountId",
7 "type": "Int",
8 "generator": "Sequence"
9 },
10 "attributes": [
11 {
12 "name": "accountId",
13 "type": "Int"
14 },
15 {
16 "name": "accountName",
17 "type": "String"
18 },
19 {
20 "name": "balanceDue",
21 "type": "Double"
22 }
23 ],
24 "relationships": [
25 {
26 "name": "invoices",
27 "inverse": "account",
28 "inverseClass": "Invoice",
29 "type": "OneToMany",
30 "cascadePolicy": "None",
31 "fetchPolicy": "Lazy"
32 }
33 ]
34 },
35 {
36 "name": "Invoice",
37 "identifier": {
38 "name": "invoiceId",
39 "type": "Long",
40 "generator": "None"
41 },
42 "attributes": [
43 {
44 "name": "invoiceId",
45 "type": "Long"
46 },
47 {
48 "name": "invoiceDate",
49 "type": "Date"
50 },
51 {
52 "name": "dueDate",
53 "type": "Date"
54 },
55 {
56 "name": "amount",
57 "type": "Double"
58 },
59 {
60 "name": "notes",
61 "type": "String"
62 }
63 ],
64 "relationships": [
65 {
66 "name": "payments",
67 "inverse": "invoice",
68 "inverseClass": "Payment",
69 "type": "OneToOne",
70 "cascadePolicy": "Save",
71 "fetchPolicy": "Eager"
72 },
73 {
74 "name": "account",
75 "inverse": "invoices",
76 "inverseClass": "Account",
77 "type": "ManyToOne"
78 }
79 ]
80 },
81 {
82 "name": "Payment",
83 "identifier": {
84 "name": "paymentId",
85 "type": "Long",
86 "generator": "None"
87 },
88 "attributes": [
89 {
90 "name": "paymentId",
91 "type": "Long"
92 },
93 {
94 "name": "amount",
95 "type": "Double"
96 },
97 {
98 "name": "notes",
99 "type": "String"
100 }
101 ],
102 "relationships": [
103 {
104 "name": "invoice",
105 "inverse": "payments",
106 "inverseClass": "Invoice",
107 "type": "OneToOne"
108 }
109 ]
110 }
111 ],
112 "revisionDescription": "Initial schema for model updates"
113 }
- Ensure your schema defines all required attributes, including types and relationships.
- The
identifier
field is mandatory for each table and must include a unique name and a supported generator type. - Relationships must have a valid name and specify both an
inverse
property andinverseClass
that refer to the corresponding related table and attribute.
2
Modify the Account Entity
Update the JSON schema to reflect changes in the Account entity, such as adding, removing, or changing attributes. Next, deploy the schema changes
1{
2 "tables": [
3 {
4 "name": "Account",
5 "identifier": {
6 "name": "accountId",
7 "type": "Long",
8 "generator": "None"
9 },
10 "attributes": [
11 {
12 "name": "accountId",
13 "type": "Long"
14 },
15 {
16 "name": "accountHolderName",
17 "type": "String"
18 },
19 {
20 "name": "accountName",
21 "type": "String"
22 }
23 // Note: Removed "balanceDue" attribute
24 ],
25 "relationships": [
26 {
27 "name": "invoices",
28 "inverse": "account",
29 "inverseClass": "Invoice",
30 "type": "OneToMany",
31 "cascadePolicy": "None",
32 "fetchPolicy": "Lazy"
33 }
34 ]
35 }
36 // ... other tables remain the same
37 ],
38 "revisionDescription": "Modified Account entity"
39 }
- The
accountHolderName
attribute was added. - The
balanceDue
attribute was removed. - The identifier's type has been changed from
Int
toLong
.
3
Verify New Fields
Retrieve the account using a
Long
rather than an Int
and verify that new fields are working as expected.1// Fetch an account. Notice that the id is now a Long rather than an Int.
2 const account = await db.findById('Account', 1);
3 console.assert(account.accountId === 1);
4
5 // The accountHolderName is a new field and is now persistable.
6 // This demonstrates that we can now take advantage of the new field.
7 account.accountHolderName = "Utility Bill";
8 await db.save('Account', account);
9
10 // Verify it was indeed persisted
11 const updatedAccount = await db.findById('Account', 1);
12 console.assert(updatedAccount.accountHolderName === "Utility Bill");
- After saving the account, the
balanceDue
is no longer stored in the database since it was overwritten in the new format.
Important Notes
- Changing attribute types is supported if the original type can be converted to the new type. You may not be able to take advantage of the lightweight migration if you were to change the type from a
Long
to anInt
or from aString
to a numeric value. - Removing a field does not delete the data; it still exists and is accessible through other means.
- Adding a new field allows you to take advantage of new attributes in your model.
Troubleshooting
- Type Conversion Errors: Ensure that the original type can be converted to the new type. For example, converting an
Int
to aLong
is acceptable, but converting aString
to a numeric type may cause issues. - Data Not Reflecting Changes: After modifying the model, ensure that you re-initialize the database connection and reload any entities.
- Missing Data After Removing Fields: Remember that removing a field from your model does not delete the data from the database. The data is still there and can be accessed using lower-level APIs if necessary.
Next Steps
Now that you have learned how to update attributes within your model, you can explore more advanced topics: