Relations
A Relation
object represents one record pointing to another — such as the author (User
) of a Comment
, or the Post
the comment belongs to.
Defining Relations
There's two steps to defining a relation:
A table column for the related record's ID
tableSchema({
name: 'comments',
columns: [
// ...
{ name: 'author_id', type: 'string' },
]
}),A
@relation
field defined on aModel
class:import { relation } from '@nozbe/watermelondb/decorators'
class Comment extends Model {
// ...
@relation('users', 'author_id') author
}The first argument is the table name of the related record, and the second is the column name with an ID for the related record.
immutableRelation
If you have a relation that cannot change (for example, a comment can't change its author), use @immutableRelation
for extra protection and performance:
import { immutableRelation } from '@nozbe/watermelondb/decorators'
class Comment extends Model {
// ...
@immutableRelation('posts', 'post_id') post
@immutableRelation('users', 'author_id') author
}
Relation API
In the example above, comment.author
returns a Relation
object.
Remember, WatermelonDB is a lazily-loaded database, so you don't get the related
User
record immediately, only when you explicitly fetch it
Observing
Most of the time, you connect Relations to Components by using observe()
(the same as with Queries):
withObservables(['comment'], ({ comment }) => ({
comment,
author: comment.author, // shortcut syntax for `author: comment.author.observe()`
}))
The component will now have an author
prop containing a User
, and will re-render both when the user changes (e.g. comment's author changes its name), but also when a new author is assigned to the comment (if that was possible).
Fetching
To simply get the related record, use fetch
. You might need it in a Writer
const author = await comment.author.fetch()
// Shortcut syntax:
const author = await comment.author
Note: If the relation column (in this example, author_id
) is marked as isOptional: true
, fetch()
might return null
.
ID
If you only need the ID of a related record (e.g. to use in an URL or for the key=
React prop), use id
.
const authorId = comment.author.id
Assigning
Use set()
to assign a new record to the relation
await database.get('comments').create(comment => {
comment.author.set(someUser)
// ...
})
Note: you can only do this in the .create()
or .update()
block.
You can also use set id
if you only have the ID for the record to assign
await comment.update(() => {
comment.author.id = userId
})
Advanced relations
Many-To-Many Relation
If for instance, our app Post
s can be authored by many User
s and a user can author many Post
s. We would create such a relation following these steps:-
- Create a pivot schema and model that both the
User
model andPost
model has association to; sayPostAuthor
- Create has_many association on both
User
andPost
pointing toPostAuthor
Model - Create belongs_to association on
PostAuthor
pointing to bothUser
andPost
- Retrieve all
Posts
for a user by defining a query that uses the pivotPostAuthor
to infer thePost
s that were authored by the User.
import { lazy } from '@nozbe/watermelondb/decorators'
class Post extends Model {
static table = 'posts'
static associations = {
post_authors: { type: 'has_many', foreignKey: 'post_id' },
}
@lazy
authors = this.collections
.get('users')
.query(Q.on('post_authors', 'post_id', this.id));
}
import { immutableRelation } from '@nozbe/watermelondb/decorators'
class PostAuthor extends Model {
static table = 'post_authors'
static associations = {
posts: { type: 'belongs_to', key: 'post_id' },
users: { type: 'belongs_to', key: 'user_id' },
}
@immutableRelation('posts', 'post_id') post
@immutableRelation('users', 'user_id') user
}
import { lazy } from '@nozbe/watermelondb/decorators'
class User extends Model {
static table = 'users'
static associations = {
post_authors: { type: 'has_many', foreignKey: 'user_id' },
}
@lazy
posts = this.collections
.get('posts')
.query(Q.on('post_authors', 'user_id', this.id));
}
withObservables(['post'], ({ post }) => ({
authors: post.authors,
}))
Next steps
➡️ Now the last step of this guide: understand Writers (and Readers)