How Dynamo DB manages Many to Many relationship? - graphql

I have 2 tables User and Activity with a Many to Many relationship:
type User #model #auth(rules: [{allow: public}]) {
id: ID!
activities: [Activity] #manyToMany(relationName: "UserActivity")
}
type Activity #model #auth(rules: [{allow: public}]) {
id: ID!
users: [User] #manyToMany(relationName: "UserActivity")
}
From Dynamo DB how should I add my JSON data to connect these 2 tables?

The relationship #manyToMany, as documented here, is completely different from all others, it configures a "join table" between two models.
Basically, after push your new GraphQL schema, in Dynamo DB you'll find a new table:
type UserActivity {
id: ID!
userID: ID!
activityID: ID!
user: User!
activity: Activity!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
Here you have to provide 2 different ID (userID and activityID) every time you want to join these 2 tables.
So you don't have to add IDs to single tables (User, Activity) but only to the joined table (UserActivity)

Related

Add many to many connection in amplify graphql

I have a time consuming problem and no idea what I can test more.
This is working, but I need the in Recruiter for positions an array. But then I have a many to many connection and nothing is working anymore. Is there a nice way to solve it?
Here is my code:
type Position #model #auth(rules: []) {
id: ID!
title: String!
candidates: [Candidate]! #connection(name: "PositionCandidates")
interestedRecruiters: [Recruiter]! #connection(name: "PositionRecruiter")
}
type Candidate #model #auth(rules: []) {
id: ID!
firstname: String!
lastname: String!
email: AWSEmail!
birthday: AWSDate!
position: Position! #connection(name: "PositionCandidates")
}
type Recruiter #model #auth(rules: []) {
id: ID!
firstname: String!
lastname: String!
email: AWSEmail!
birthday: AWSDate!
positions: Position! #connection(name: "PositionRecruiter")
}
thanks !
To work with many-to-many connections with amplify/app sync you have to create a 'Join' table (type). You can think of the join table as a table where you store the connections.
I didn't completely understand from your example what you wanted the result to be, so I'll try to explain with an alternate example:
Lets say you have a system where multiple users can be the creators of a document, and a user also can be one of the creators of multiple documents. To accomplish this you must create three dynamoDb tables (or three types is the schema).
type User #model {
id: ID!
name: String
documents: [UserDocument] #connection(name: "UserDocumentConnection")
}
type Document #model {
id: ID!
title: String
content: String
users: [UserDocument] #connection(name: "DocumentUserConnection")
}
type UserDocument #model {
id: ID!
user: User #connection(name: "UserDocumentConnection")
document: Document #connection(name: "DocumentUserConnection")
}
Then you have a table containing all your users, a table containing all your Documents, and a table containing all the connections between users and documents.
So let's say you have a users that is creating a new document. Then you first create the document, then when it is created and you have received the document back from appsync with the new id of the document, then you must create a new object in the UserDocument table, containing the id of the user and the id of the document. You can then also add more users on the document by adding more items to the UserDocument table.
I hope this will help you to the correct path forwards.

How can I condition GraphQL mutation based on exists?

I am creating schemas in GraphQl and testing these in Playground. These seem to work fine in being able to create Club, User and Team, yet I only want to be able to create a team if a club exists and can therefore connect to the club. At the moment I can create a team without a club existing, which of course shouldn't happen. On create Team Mutation, I also want to stop any club being created, the club must exist prior to any mutation on a Team.
Here is what I have at the moment for my schemas
type Club {
id: ID! #unique
name: String! #unique
team: [Team!]! #relation(name: "TeamToClub", onDelete: CASCADE)
admin: User! #relation(name: "UserToClub", onDelete: SET_NULL)
}
type User {
id: ID! #unique
name: String!
team: [Team!]! #relation(name: "TeamToUser", onDelete: SET_NULL)
club: [Club!]! #relation(name: "UserToClub", onDelete: SET_NULL)
}
type Team {
id: ID! #unique
name: String!
club: Club! #relation(name: "TeamToClub", onDelete: SET_NULL)
creator: User! #relation(name: "TeamToUser", onDelete: SET_NULL)
coach:[Coach!]! #relation(name: "CoachToTeam", onDelete: SET_NULL)
}
Here are my mutations for creating a user
mutation {
createUser(
data:{
name:"Jack Jones",
email:"jack#example.com"
}
){
id
name
}
}
and creating a team..
mutation {
createTeam(
data:{
title:"Barcelona FC"
agegroup:"Under 12s",
published: false,
coachcreator:{
connect:{
id:"cka8qkd5h02dj0815m3odzh5s"
}
}
}
){
id
title
agegroup
published
coachcreator {
name
}
}
}
both of which work without connecting to a club.
Could anybody provide a possible solution to ensure a condition is in place to say a team can only be created when a club already exists.
Strange mutations - looks like they are completely not related to types.
Usually create mutation returns created type, f.e. createUser returns User ... and mutation argument - input type (UserInput) - with almost the same shape as returned type (without id).
The simplest method to ensure that createTeam has proper (existing) club relation is to define club as required argument of mutation.

Same type relationships in GraphQL / Prisma

I am trying to create a one-to-many relation of the same type. In this case, a user can report to one user and in turn have many users reporting to them.
My data model currently looks like this:
type User {
id: ID! #id
name: String!
email: String! #unique
reportsTo: User #relation(name: "UserReports")
reports: [User] #relation(name: "UserReports")
}
I expect adding a userId to reportsTo should add the corresponding user's ID to reports.
However, adding a userId to reportsTo is adding the userId to the same user's reports, rather than other users reports.
You can't have a relationship with different elements of the one type. A relation is connecting two different types so we know they share information. Therefore we need to create some addition types that we can base a relationship on.
I've created two different types, one a "supervisor" who is a user who supervises other users, but we will have those users as a second type, "supervisee". Each user can be both a supervisor and a supervisee. There is a relation between a user and each of these two types and a relation between these two types as well.
This is the datamodel:
type User {
id: ID! #id
name: String!
email: String! #unique
supervisor: Supervisor #relation(name: "UserToSupervisor")
supervisee: Supervisee #relation(name: "UserToSupervisee")
}
type Supervisor {
id: ID! #id
user: User! #relation(name: "UserToSupervisor")
supervisees: [Supervisee!]! #relation(name: "SupervisorToSupervisee")
}
type Supervisee {
id: ID! #id
user: User! #relation(name: "UserToSupervisee")
supervisor: Supervisor! #relation(name: "SupervisorToSupervisee")
}
You must view the "supervisor" field in user not as who that users supervior is, but that the user might be a supervisor themselves. This is also the case with supervisee. Basically supervisor and supervisee are extensions of user and the working relationship between them is defined between those two types.

Prisma data modeling has many and belongs to

I have a prisma data model that consists of a root Category and a Subcategory. A Category has many Subcategories and a Subcategory belongs to one Category. My model looks like this:
type Category {
id: ID! #unique
createdAt: DateTime!
updatedAt: DateTime!
name: String!
subCategories: [SubCategory!]! #relation(name: "Subcategories")
}
type SubCategory {
id: ID! #unique
createdAt: DateTime!
updatedAt: DateTime!
name: String!
category: Category! #relation(name: "ParentCategory")
cards: [Card!]! #relation(name: "SubCategoryCards") #Category #relation(name: "CardCategory")
}
Now when i go to create a new subcategory and via
mutation {
createSubCategory(data:{
name:"This is a test"
category:{
connect:{
id:"cjp4tyy8z01a6093756xxb04i"
}
}
}){
id
category{
name
id
}
}
}
This appears to work fine. Below I query for the subcategories and their parent Category and I get the results that I expect.
{
subCategories{
id
name
category{
id
name
}
}
}
However, when i try to query a category, and get all of it's sub categories I'm getting an empty array:
{
categories{
id
name
subCategories{
id
name
}
}
}
How can I query all categories and get their sub categories?
As per the documentation, the #relation directive is used to specify both ends of a relation.
Let's take the following datamodel:
type User {
postsWritten: [Post!]!
postsLiked: [Post!]!
}
type Post {
author: User!
likes: [User!]!
}
Here, we have an ambiguous relation between Post and User. Prisma needs to know which User field (postsWritten? postsLiked?) to link to which Post field (author? likes?)
To resolve this, we use the #relation with a name used in both ends of the relation.
This would make the datamodel look like this:
type User {
postsWritten: [Post!]! #relation(name: "AuthorPosts")
postsLiked: [Post!]! #relation(name: "UserLikes")
}
type Post {
author: User! #relation(name: "AuthorPosts")
likes: [User!]! #relation(name: "UserLikes")
}
Because we used the same name for the postsWritten and author fields, Prisma is now able to link these two in the database. Same for postsLiked and likes.
In conclusion, the problem with your datamodel is that you used different names in your relation. This confuses Prisma which think those are different relations. Which explains why you can query one way but not another.

GraphQL Prisma - define "vote" type that links to two users

I've just started using Prisma. Before was mainly using firebase and mongodb to define my schemas.
I'm trying to define the following schema:
Vote {
id: ID!
from: User! # The user who voted
for: User! # The user that received a vote
rate: Float!
}
Basically, what I want to achieve is enable users to vote for other users (give them a score).
In, say, MongoDB I would do it by creating a separate collection like following:
{
id: DocumentID
from: String // id of the user who voted
for: String // id of the user that received a vote
rate: Number
}
In here I just specify those fields (from and for) as strings and after link them with the User collection by the application logic.
For sure, it's gonna be different in GraphQL Prisma. But I'm still a bit confused on how the relationships are built. And what really happens underneath.
How can I create such schema using Prisma GraphQL?
When there are more than one relational field to the same type, you need to use the #relation directive to make it unambiguous.
type Vote {
id: ID! #unique
votingUser: User! #relation(name: "VoteAuthor")
votedUser: User! #relation(name: "VoteReceiver")
rate: Float!
}
type User {
id: ID! #unique
receivedVotes: [Vote!]! #relation(name: "VoteReceiver")
givenVotes: [Vote!]! #relation(name: "VoteAuthor")
name: String!
}

Resources