0
# Relationships and Eager Loading
1
2
Relationship definitions and eager loading patterns for efficient data fetching.
3
4
## Capabilities
5
6
### Relation Types
7
8
Objection.js provides five relation types for modeling database relationships.
9
10
```javascript { .api }
11
/**
12
* One-to-one relation where foreign key is in related table
13
*/
14
const HasOneRelation: RelationType;
15
16
/**
17
* One-to-many relation
18
*/
19
const HasManyRelation: RelationType;
20
21
/**
22
* Many-to-one relation where foreign key is in owner table
23
*/
24
const BelongsToOneRelation: RelationType;
25
26
/**
27
* Many-to-many relation through junction table
28
*/
29
const ManyToManyRelation: RelationType;
30
31
/**
32
* One-to-one relation through junction table
33
*/
34
const HasOneThroughRelation: RelationType;
35
```
36
37
### Relation Mapping
38
39
Configuration object for defining relationships between models.
40
41
```javascript { .api }
42
/**
43
* Relation mapping configuration
44
*/
45
interface RelationMapping {
46
relation: RelationType;
47
modelClass: typeof Model | string | (() => typeof Model);
48
join: RelationJoin;
49
modify?: string | ((query: QueryBuilder) => void);
50
filter?: string | ((query: QueryBuilder) => void);
51
beforeInsert?: (model: Model, context: QueryContext) => void | Promise<void>;
52
}
53
54
interface RelationJoin {
55
from: string | string[];
56
to: string | string[];
57
through?: RelationThrough;
58
}
59
60
interface RelationThrough {
61
from: string | string[];
62
to: string | string[];
63
modelClass?: typeof Model | string | (() => typeof Model);
64
extra?: string | string[] | Record<string, string>;
65
modify?: string | ((query: QueryBuilder) => void);
66
filter?: string | ((query: QueryBuilder) => void);
67
beforeInsert?: (model: Model, context: QueryContext) => void | Promise<void>;
68
}
69
```
70
71
**Usage Examples:**
72
73
```javascript
74
class Person extends Model {
75
static get tableName() {
76
return 'persons';
77
}
78
79
static get relationMappings() {
80
return {
81
// Has many pets
82
pets: {
83
relation: Model.HasManyRelation,
84
modelClass: Pet,
85
join: {
86
from: 'persons.id',
87
to: 'pets.ownerId'
88
}
89
},
90
91
// Belongs to one parent
92
parent: {
93
relation: Model.BelongsToOneRelation,
94
modelClass: Person,
95
join: {
96
from: 'persons.parentId',
97
to: 'persons.id'
98
}
99
},
100
101
// Many-to-many movies through junction table
102
movies: {
103
relation: Model.ManyToManyRelation,
104
modelClass: Movie,
105
join: {
106
from: 'persons.id',
107
through: {
108
from: 'persons_movies.personId',
109
to: 'persons_movies.movieId',
110
extra: ['role', 'salary'] // Additional columns from junction table
111
},
112
to: 'movies.id'
113
}
114
},
115
116
// Has one through relation
117
passport: {
118
relation: Model.HasOneThroughRelation,
119
modelClass: Passport,
120
join: {
121
from: 'persons.id',
122
through: {
123
from: 'person_details.personId',
124
to: 'person_details.passportId'
125
},
126
to: 'passports.id'
127
}
128
}
129
};
130
}
131
}
132
```
133
134
### Eager Loading
135
136
Methods for loading related data efficiently.
137
138
```javascript { .api }
139
/**
140
* Eagerly fetch related models using joins
141
* @param expression - Relation expression string
142
* @param options - Graph options
143
* @returns QueryBuilder instance
144
*/
145
withGraphJoined(expression: string, options?: GraphOptions): QueryBuilder;
146
147
/**
148
* Eagerly fetch related models using separate queries
149
* @param expression - Relation expression string
150
* @param options - Graph options
151
* @returns QueryBuilder instance
152
*/
153
withGraphFetched(expression: string, options?: GraphOptions): QueryBuilder;
154
155
/**
156
* Fetch graph for existing model instances
157
* @param models - Model instance(s) to fetch relations for
158
* @param expression - Relation expression
159
* @param options - Fetch options
160
* @returns Promise resolving to models with relations
161
*/
162
static fetchGraph(
163
models: Model | Model[],
164
expression: string,
165
options?: FetchGraphOptions
166
): Promise<Model | Model[]>;
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
// Basic eager loading
173
const people = await Person.query()
174
.withGraphFetched('pets')
175
.where('age', '>', 18);
176
177
// Nested relations
178
const people = await Person.query()
179
.withGraphFetched('pets.owner.movies')
180
.limit(10);
181
182
// Multiple relations
183
const people = await Person.query()
184
.withGraphFetched('[pets, movies, parent.pets]');
185
186
// With filtering
187
const people = await Person.query()
188
.withGraphFetched('pets(selectName)')
189
.modifiers({
190
selectName(builder) {
191
builder.select('name');
192
}
193
});
194
195
// Using aliases
196
const people = await Person.query()
197
.withGraphFetched('pets as animals, movies as films');
198
```
199
200
### Relation Expression Syntax
201
202
String syntax for specifying which relations to load.
203
204
```javascript { .api }
205
// Basic relation
206
'pets'
207
208
// Nested relations (dot notation)
209
'pets.owner'
210
'pets.owner.movies'
211
212
// Multiple relations (array notation)
213
'[pets, movies]'
214
'[pets, movies, parent]'
215
216
// Mixed nested and multiple
217
'[pets.owner, movies.actors]'
218
219
// With modifiers (parentheses)
220
'pets(selectName)'
221
'movies(filterPopular).actors(selectName)'
222
223
// With aliases (as keyword)
224
'pets as animals'
225
'movies as films'
226
'pets.owner as petOwner'
227
228
// Complex expressions
229
'[pets(selectName) as animals, movies(filterPopular).actors]'
230
```
231
232
### Related Query Building
233
234
Methods for querying related models.
235
236
```javascript { .api }
237
/**
238
* Create query for related models at class level
239
* @param relationName - Name of the relation
240
* @param trx - Optional transaction
241
* @returns QueryBuilder for related models
242
*/
243
static relatedQuery(relationName: string, trx?: Transaction): QueryBuilder;
244
245
/**
246
* Create query for related models at instance level
247
* @param relationName - Name of the relation
248
* @param trx - Optional transaction
249
* @returns QueryBuilder for related models
250
*/
251
$relatedQuery(relationName: string, trx?: Transaction): QueryBuilder;
252
```
253
254
**Usage Examples:**
255
256
```javascript
257
// Query all pets of a specific person
258
const personId = 1;
259
const pets = await Person.relatedQuery('pets')
260
.for(personId)
261
.where('species', 'dog');
262
263
// Query pets for a person instance
264
const person = await Person.query().findById(1);
265
const pets = await person.$relatedQuery('pets')
266
.where('species', 'cat');
267
268
// Insert related model
269
await person.$relatedQuery('pets')
270
.insert({ name: 'Fluffy', species: 'cat' });
271
272
// Update related models
273
await person.$relatedQuery('pets')
274
.patch({ vaccinated: true })
275
.where('age', '<', 1);
276
```
277
278
### Relation Manipulation
279
280
Methods for connecting and disconnecting related models.
281
282
```javascript { .api }
283
/**
284
* Relate existing models
285
* @param ids - IDs or model instances to relate
286
* @returns QueryBuilder instance
287
*/
288
relate(ids: any | any[] | Model | Model[]): QueryBuilder;
289
290
/**
291
* Unrelate models (remove relationship)
292
* @returns QueryBuilder instance
293
*/
294
unrelate(): QueryBuilder;
295
296
/**
297
* Specify which models to operate on
298
* @param ids - IDs to target for operation
299
* @returns QueryBuilder instance
300
*/
301
for(ids: any | any[]): QueryBuilder;
302
```
303
304
**Usage Examples:**
305
306
```javascript
307
// Relate existing models
308
await person.$relatedQuery('movies')
309
.relate([1, 2, 3]); // Movie IDs
310
311
// Unrelate specific models
312
await person.$relatedQuery('movies')
313
.unrelate()
314
.where('released', '<', '2000-01-01');
315
316
// Unrelate all
317
await person.$relatedQuery('movies')
318
.unrelate();
319
320
// Complex relation with extra properties (many-to-many)
321
await person.$relatedQuery('movies')
322
.relate({
323
id: 1,
324
role: 'Actor',
325
salary: 100000
326
});
327
```
328
329
### Modify Graph Relations
330
331
Modify related queries during eager loading.
332
333
```javascript { .api }
334
/**
335
* Modify related queries in graph fetching
336
* @param expression - Relation expression to modify
337
* @param modifier - Modifier function or name
338
* @returns QueryBuilder instance
339
*/
340
modifyGraph(
341
expression: string,
342
modifier: string | ((query: QueryBuilder) => void)
343
): QueryBuilder;
344
```
345
346
**Usage Examples:**
347
348
```javascript
349
const people = await Person.query()
350
.withGraphFetched('pets')
351
.modifyGraph('pets', builder => {
352
builder.where('species', 'dog').orderBy('name');
353
});
354
355
// Using named modifiers
356
const people = await Person.query()
357
.withGraphFetched('pets(onlyDogs)')
358
.modifiers({
359
onlyDogs(builder) {
360
builder.where('species', 'dog');
361
}
362
});
363
```
364
365
## Types
366
367
```javascript { .api }
368
type RelationType = {
369
new (): Relation;
370
};
371
372
type RelationExpression = string | object;
373
374
interface GraphOptions {
375
minimize?: boolean;
376
separator?: string;
377
aliases?: Record<string, string>;
378
joinOperation?: string;
379
maxBatchSize?: number;
380
}
381
382
interface FetchGraphOptions {
383
transaction?: Transaction;
384
skipFetched?: boolean;
385
}
386
387
interface Relation {
388
name: string;
389
ownerModelClass: typeof Model;
390
relatedModelClass: typeof Model;
391
joinModelClass?: typeof Model;
392
joinTable?: string;
393
}
394
```