The “HMT” association is one of the very nice things about Rails and Active Record – and something many people moving to Prisma yearn for to be similar or simpler.
It’s been brought here here in this Community:
and in Prisma as well:
In short, I believe people are solving it – just like you noted above – via the “many-to-many” with Prisma’s implicit or explicit approach:
So a User
and a Role
and either an implicitly created _UserToRole
or an explicitly UserRole
join table or as they would name it RolesOnUsers
.
The problem seen with the implicit table – and something I wish Prisma would improve on is that:
- there are no timestamps on
_UserToRole
so you don’t know when a user was assigner a Role - You cannot store any other metadata or info on that join table
To do that would have to use the explicit method.
Ok - so back to your question
I expected to be able to query something like:
query FIND_USER_BY_ID($id: Int!) {
user: user(id: $id) {
firstName
lastName
roles {
name
id
}
}
}
In a project I am working on now, I have two models Tweet
and Article
where a there is a many to many relationship because a Tweet could have mentioned an article and so could many other tweets (where the article is defined by its url):
This diagram shows the join table without the
_
– this is the implicit _ArticleToTweet
When I am viewing the Tweet and I want to see the Article(s), my Prisma query is:
export const tweetById = ({ id }) => {
return db.tweet.findOne({
where: { id: id },
include: {
entry: true,
articles: {
include: {
tags: { where: { confidence: { gte: 0.4 }, mentions: { gt: 0 } } },
},
},
tweetContext: true,
tweetCategories: true,
tags: { where: { confidence: { gte: 0.4 }, mentions: { gt: 0 } } },
tweetPriorities: true,
},
})
}
Very Important! I also need:
export const Tweet = {
articles: (_obj, { root }) =>
db.tweet.findOne({ where: { id: root.id } }).articles(),
}
export const Article = {
tweets: (_obj, { root }) =>
db.article.findOne({ where: { id: root.id } }).tweets()
}
And you might think this should be
findMany
and I did at first, too, but really this is saying “for each Article” there are many Tweets and vice versa when resolving in GraphQL (or that’s how I’ve understood it to work).
And in my cell to show the Tweet and the Article included to match the Prisma is:
export const QUERY = gql`
query TweetQuery($id: String!) {
tweet: tweetById(id: $id) {
id
createdAt
updatedAt
publishedAt
author
title
content
sentiment
url
articles {
id
title
description
url
tags {
label
mentions
confidence
salience
sentiment
}
}
categories: tweetCategories {
label
}
priorities: tweetPriorities {
label
terms: tweetPriorityTerms {
label
}
}
tags {
label
mentions
confidence
salience
sentiment
entityTypes
}
}
}
`
And you can see that I can get both the Article on Tweet and Tweet on the Article:
Is it that same as a has_many through – maybe, maybe not.
So, far this is working, but it does take awhile to get comfortable.
That said, can see Prisma trying to work in some familiar Active Record -like features in their Nested Writes where they have a connectOrCreate
which is similar to the find_or_create_by (or first_or_create_by
).
As with many things, I hope Prisma will evolve to help make these things a bit easier.
Thanks for reading.