HasMany Relationship
The HasMany relationship represents a one-to-many relationship where the foreign model stores a reference to the current model.
Explanation
For example, a User has many Posts:
Defining the Relationship
The relationship is defined in your model configuration under the relationships
property as a tuple:
typescript
[HasMany, foreignModelTable: string, foreignKey: string, originatingPrimaryKey?: string, foreignPrimaryKey?: string]
Required Parameters
HasMany
: The relationship typeforeignModelTable
: The table name of the related modelforeignKey
: The foreign key in the related model that references the current model
Optional Parameters
originatingPrimaryKey
: The primary key in the current model (defaults to 'id')foreignPrimaryKey
: The primary key in the foreign model (defaults to 'id')
Example
typescript
{
models: {
users: {
schema: '++id, email, createdAt, updatedAt',
properties: ['id', 'email', 'password'],
primaryKey: 'id',
relationships: {
posts: [HasMany, 'posts', 'user_id'],
}
},
posts: {
schema: '++id, user_id, title, body, created_at',
properties: ['id', 'user_id', 'title', 'body', 'created_at'],
}
}
}
In this example:
- The Post model has a
user_id
foreign key that references the User model'sid
- The relationship is defined as
[HasMany, 'posts', 'user_id']
where:'posts'
is theforeignModelTable
'user_id'
is theforeignKey
- The primary keys default to 'id' since they're not specified
Accessing the Relationship
typescript
// Get all posts for a user
const user = await User.find(1)
const posts = await user.posts
// The relationship is reactive for both individual posts and the collection
posts.forEach(post => {
post.onChange((updatedPost) => {
console.log('Post updated:', updatedPost)
})
})
user.onPropertyChange('posts', (newPosts, oldPosts) => {
console.log('Posts collection changed:', {
new: newPosts,
old: oldPosts
})
})
// You can also eager load the relationship
const users = await User.query()
.with('posts')
.fetch()
Working with Collections
HasMany relationships return an array of model instances that you can manipulate using standard array methods:
typescript
// Filter posts
const publishedPosts = user.posts.filter(post => post.published)
// Sort posts by date
const sortedPosts = user.posts.sort((a, b) =>
new Date(b.created_at) - new Date(a.created_at)
)
// Map to get just the titles
const postTitles = user.posts.map(post => post.title)
// Count posts
const postCount = user.posts.length
You can also use the query builder to fetch related records with conditions:
typescript
// Get users with their published posts
const users = await User.query()
.with('posts')
.where(user => user.posts.some(post => post.published))
.fetch()