Relations Overview
Hysteria ORM supports rich relation types between models:
| Relation | Description |
|---|---|
belongsTo | Inverse of hasOne/hasMany |
hasOne | One-to-one relationship |
hasMany | One-to-many relationship |
manyToMany | Many-to-many via join table |
Relations use batch loading—one query per relation, only when load is called.
caution
Loading too many relations can slow down your query. Be selective about what you load.
Example Models
class User extends Model {
@hasMany(() => Post, 'userId')
declare posts: Post[];
@manyToMany(() => Address, () => UserAddress, {
leftForeignKey: 'userId',
rightForeignKey: 'addressId',
})
declare addresses: Address[];
}
class Post extends Model {
@column({ type: 'integer', primaryKey: true })
declare id: number;
@column({ type: 'integer' })
declare userId: number;
// Belongs to does not benefit from type inference by default for typescript limitations, it's adviced to use the generic type to avoid type errors
@belongsTo<typeof Post>(() => User, 'userId') // With the generic we are obligated to specify a model field
declare user: User;
}
class Address extends Model {
@manyToMany(() => User, () => UserAddress, {
leftForeignKey: 'addressId',
rightForeignKey: 'userId',
})
declare users: User[];
}
Querying Relations
important
Always select the foreign key in the relation query builder, otherwise the relation will not be filled.
Eager Loading
const users = await User.query().load('posts').many();
Selecting Columns
The foreign key (userId) must be selected for relations to work:
const users = await User.query().load('posts', (qb) =>
qb.select('id', 'title', 'userId')
).many();
Nested Relations
const users = await User.query().load('posts', (qb) =>
qb.load('user')
).many();
Filtering on Relations
const users = await User.query().load('posts', (qb) =>
qb.where('title', 'Hello World')
).many();
Limit and Offset
Limit and offset apply to the related models. Adding limit or offset creates a CTE internally.
const users = await User.query().load('posts', (qb) =>
qb.where('title', 'Hello World').limit(10).offset(10)
).many();
Advanced relation queries
const users = await User.query().load('posts', (qb) =>
qb.annotate("max", "id", "maxId").load("user")
).many();
Best Practices
- Use
loadfor batch relation loading. - Use callbacks for nested and filtered relations.
- Always define foreign keys explicitly for clarity.
Next: Advanced SQL Features