or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

expression-builders.mdgraph-operations.mdindex.mdmodel-definition.mdquery-building.mdrelationships.mdtransactions.mdutilities.mdvalidation.md

relationships.mddocs/

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

```