# Relationships: One To Many
A one-to-many relationship is used to define relationships where a single model owns any amount of other models. For example, a blog post may have an infinite number of comments. Vuex ORM provides the relationship attribute to define such a relationship.
# Defining The One To Many Relationship
Like all other Vuex ORM relationships, one-to-many relationships are defined by placing a relationship attribute as a model field. As for one-to-many relationship, you may define the field using the hasMany
attribute. You may define the Post
model that has many Comment
models as shown below:
class Post extends Model {
static entity = 'posts'
static fields () {
return {
id: this.attr(null),
title: this.string(''),
comments: this.hasMany(Comment, 'postId')
}
}
}
class Comment extends Model {
static entity = 'comments'
static fields () {
return {
id: this.attr(null),
postId: this.attr(null),
body: this.string('')
}
}
}
The first argument passed to the hasMany
method is the related model, and the second argument is the foreign key.
Remember that Vuex ORM assumes that the foreign key should have a value matching the id
(or the custom static primaryKey
) field of the parent. Vuex ORM will look for the value of the user's id
field in the userId
field of the Comment record. If you would like the relationship to use a value other than id
, you may pass a third argument to the hasMany
method specifying your custom key:
class Post extends Model {
static entity = 'posts'
static fields () {
return {
id: this.attr(null),
localId: this.attr(null),
title: this.string(''),
comments: this.hasMany(Comment, 'postId')
}
}
}
# One To Many (Inverse)
Now that we can access all of a post's comments let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany
relationship, define a relationship on the child model, which calls the belongsTo
method just like with the hasOne
relation:
class Comment extends Model {
static entity = 'comments'
static fields () {
return {
id: this.attr(null),
postId: this.attr(null),
body: this.string(''),
post: this.belongsTo(Post, 'postId')
}
}
}
In the example above, Vuex ORM will try to match the postId
from the Comment
model to an id
on the Post
model.
If your parent model does not use id
as its primary key, or you wish to join the child model to a different field, you may pass a third argument to the belongsTo
method specifying your parent model's custom key:
class Comment extends Model {
static entity = 'comments'
static fields () {
return {
id: this.attr(null),
postId: this.attr(null),
body: this.string(''),
post: this.belongsTo(Post, 'postId', 'otherKey')
}
}
}
# One To Many By
One To Many By is similar to One To Many relation but having foreign keys at parent Model as an array. For example, there could be a situation where you must parse data looks something like:
{
nodes: {
1: { id: 1, name: 'Node 01' },
2: { id: 2, name: 'Node 02' }
},
clusters: {
1: {
id: 1,
name: 'Cluster 01',
nodeIds: [1, 2]
}
}
}
As you can see, clusters
have "Has Many" relationship with nodes
, but nodes
do not have foreign key set (clusterId
). We can't use Has Many relation in this case because there is no foreign key to look for. In such cases, you may use hasManyBy
relationship.
class Node extends Model {
static entity = 'nodes'
static fields () {
return {
id: this.attr(null),
name: this.string('')
}
}
}
class Cluster extends Model {
static entity = 'clusters'
static fields () {
return {
id: this.attr(null),
nodeIds: this.attr([]),
name: this.string('')
nodes: this.hasManyBy(Node, 'nodeIds')
}
}
}
Now the Cluster model is going to look for Nodes using ids at Cluster's own nodeIds
attributes.
As always, you can pass the third argument to specify which id to look for.
class Cluster extends Model {
static entity = 'clusters'
static fields () {
return {
id: this.attr(null),
nodeIds: this.attr(null),
nodes: this.hasManyBy(Node, 'nodeIds', 'nodeId')
}
}
}