Fetch Policy Tutorial

The Fetch Policy can be used to optimize your object graph. Onyx enables developers to load only what they need. There are instances when users would like to reduce the size of the object graph in order to save memory and network overhead by lazily or not loading relationships.

PolicyDescription
EagerEager fetch policy will hydrate the entire relationship and all of the subsequent object graph.
LazyLazy fetch policy will return references to the relationship data. When referenced using the List interface, the relationship will be lazily filled in.
NoneThe relationship will not be populated upon fetching an entity. It will sometimes be populated in the event the entity is already cached.

Steps to Use Fetch Policy (Onyx Cloud Database)

1

Declare the Entities Using JSON Schema

Use the provided JSON schema to define your entities and relationships. Deploy your database using this schema definition.
1{
2  "tables": [
3    {
4      "name": "Series",
5      "identifier": {
6        "name": "seriesId",
7        "type": "String",
8        "generator": "None"
9      },
10      "attributes": [
11        {
12          "name": "seriesId",
13          "type": "String",
14          "isNullable": false
15        }
16      ],
17      "relationships": [
18        {
19          "name": "seasons",
20          "inverse": "series",
21          "inverseClass": "Season",
22          "type": "OneToMany",
23          "fetchPolicy": "Eager",
24          "cascadePolicy": "All"
25        }
26      ]
27    },
28    {
29      "name": "Season",
30      "identifier": {
31        "name": "seasonId",
32        "type": "Long",
33        "generator": "Sequence"
34      },
35      "attributes": [
36        {
37          "name": "seasonId",
38          "type": "Long",
39          "isNullable": false
40        },
41        {
42          "name": "seasonNumber",
43          "type": "Int",
44          "isNullable": false
45        },
46        {
47          "name": "seasonYear",
48          "type": "Int",
49          "isNullable": false
50        }
51      ],
52      "relationships": [
53        {
54          "name": "series",
55          "inverse": "seasons",
56          "inverseClass": "Series",
57          "type": "ManyToOne",
58          "fetchPolicy": "None",
59          "cascadePolicy": "None"
60        },
61        {
62          "name": "episodes",
63          "inverse": "season",
64          "inverseClass": "Episode",
65          "type": "OneToMany",
66          "fetchPolicy": "Lazy",
67          "cascadePolicy": "Save"
68        }
69      ]
70    },
71    {
72      "name": "Episode",
73      "identifier": {
74        "name": "episodeId",
75        "type": "String",
76        "generator": "None"
77      },
78      "attributes": [
79        {
80          "name": "episodeId",
81          "type": "String",
82          "isNullable": false
83        },
84        {
85          "name": "episodeNumber",
86          "type": "Int",
87          "isNullable": false
88        }
89      ],
90      "relationships": [
91        {
92          "name": "season",
93          "inverse": "episodes",
94          "inverseClass": "Season",
95          "type": "ManyToOne",
96          "fetchPolicy": "None",
97          "cascadePolicy": "None"
98        }
99      ]
100    },
101    {
102      "name": "Actor",
103      "identifier": {
104        "name": "actorId",
105        "type": "Int",
106        "generator": "Sequence"
107      },
108      "attributes": [
109        {
110          "name": "actorId",
111          "type": "Int",
112          "isNullable": false
113        },
114        {
115          "name": "firstName",
116          "type": "String",
117          "isNullable": true
118        },
119        {
120          "name": "lastName",
121          "type": "String",
122          "isNullable": true
123        }
124      ],
125      "relationships": []
126    }
127  ],
128  "revisionDescription": "Schema for Fetch Policy tutorial"
129}
  • Ensure that relationship types and inverse properties are correctly specified.
  • Set the appropriate fetchPolicy for each relationship to control how data is loaded.
2

Populate Test Data

Create instances of your entities and populate your object graph. Use the save function to persist the entire graph.
1// Populate some test data
2const theSopranos = {
3    seriesId: "SOPRANOS",
4    seasons: []
5};
6
7const firstSeason = {
8    seasonNumber: 1,
9    seasonYear: 1999,
10    episodes: []
11};
12
13const secondSeason = {
14    seasonNumber: 2,
15    seasonYear: 2000,
16    episodes: []
17};
18
19const thirdSeason = {
20    seasonNumber: 3,
21    seasonYear: 2001,
22    episodes: []
23};
24
25const fourthSeason = {
26    seasonNumber: 4,
27    seasonYear: 2002,
28    episodes: []
29};
30
31// Add the seasons to the sopranos
32theSopranos.seasons = [firstSeason, secondSeason, thirdSeason, fourthSeason];
33
34firstSeason.episodes = [
35    { episodeId: "s01e01", episodeNumber: 1, actors: [] },
36    { episodeId: "s01e02", episodeNumber: 2, actors: [] },
37    { episodeId: "s01e03", episodeNumber: 3, actors: [] },
38    { episodeId: "s01e04", episodeNumber: 4, actors: [] },
39    { episodeId: "s01e05", episodeNumber: 5, actors: [] }
40];
41
42secondSeason.episodes = [
43    { episodeId: "s02e01", episodeNumber: 6, actors: [] },
44    { episodeId: "s02e02", episodeNumber: 7, actors: [] },
45    { episodeId: "s02e03", episodeNumber: 8, actors: [] },
46    { episodeId: "s02e04", episodeNumber: 9, actors: [] },
47    { episodeId: "s02e05", episodeNumber: 10, actors: [] }
48];
49
50// ...
51
52const james = {
53    firstName: "James",
54    lastName: "Gandolfini"
55};
56
57const steve = {
58    firstName: "Steve",
59    lastName: "Buscemi"
60};
61
62theSopranos.seasons.forEach(season => {
63    season.episodes.forEach(episode => {
64        episode.actors = [james, steve];
65    });
66});
67
68// Save the Series. Note: This will persist the entire object graph
69await db.save(Series, theSopranos);
  • Relationships with cascade policies of CascadePolicy.SAVE or CascadePolicy.ALL will ensure related entities are persisted.
3

Fetch and Verify Eager Relationships

Retrieve a fresh copy of the Series entity to demonstrate how eager relationships are loaded.
1// Fetch a new copy of the entity to illustrate how eager relationships are fetched
2const theSopranosCopy = await db.findById(Series, theSopranos.seriesId);
3
4console.assert(theSopranosCopy.seasons != null, "Seasons should be populated because it is eagerly fetched");
5console.assert(Array.isArray(theSopranosCopy.seasons), "Seasons should be fully populated as an Array");
  • Verify that the seasons relationship is populated and fully loaded.
4

Verify Lazy Loading of Relationships

Access the episodes relationship of a Season to demonstrate lazy loading.
1// Verify that episodes are lazily loaded
2const firstSeasonCopy = theSopranosCopy.seasons[0];
3console.assert(firstSeasonCopy.episodes != null, "The first season's episodes should not be null since it is lazily loaded");
4console.assert(firstSeasonCopy.episodes instanceof LazyRelationshipCollection, "The first season's episodes should be LazyRelationshipCollection");
5
6// When we reference an episode, it gets hydrated
7const episode = firstSeasonCopy.episodes[0];
  • The episodes relationship should be lazily loaded and hydrated upon access.
  • Relationships with FetchPolicy.NONE may need explicit initialization.

Important Notes

  • Choosing the correct fetch policy is crucial for optimizing performance and memory usage.
  • Use FetchPolicy.EAGER when you need the full object graph immediately.
  • Use FetchPolicy.LAZY to defer loading until the relationship is accessed.
  • Use FetchPolicy.NONE when you do not need the relationship data or want to manually control loading.

Troubleshooting

  • Unexpected Null Relationships: Verify that your fetch policies are set correctly and that related entities are properly persisted.
  • Performance Issues: Use lazy or none fetch policies to reduce memory footprint and improve performance.
  • Data Not Loading: For relationships with FetchPolicy.NONE, use explicit initialization if needed.

Next Steps

Now that you understand how to use fetch policies to optimize your object graph, you can explore more advanced topics: