Connecting & Disconnecting many-to-many relationship

prisma

#1

For simplicity’s sake, let’s consider I have the following datamodel:

Post  {
    user: User @relation(name: "UserPost")
    name: String
}

User {
    post: Post @relation(name: "UserPost")
}

Let’s say I want to update the post to another User. The schema created would give me the following options:

  • create
  • update
  • upsert
  • delete
  • disconnect
  • connect

In this case, I would need to do two operations, ‘disconnect’ and ‘connect’ from one User to the next. Is there a way to do this with one query? Because today, I have a function that checks if the Post has a User, is so, disconnects it, and then a second query runs to connect the new one.

Want to know if I am doing this super-inefficiently or if there is an easier ‘replace’-type mechanism.


#2

Hello Ian,

You don’t have to disconnect a User to be able to connect and replace the current User. If you use the schema created ‘connect’ option it’ll create a connection or replace the old one.


#3

Understood. However, if I want to disconnect the user/post relationship (without a replacement) I must do so with ‘disconnect’, and according to this issue, I can only do so if the relationship exists, otherwise an Error is thrown — correct?

I ask because I have some very suspect logic because I do not know if the client is going to feed me a A) net-new connection B) replacement connection or C) a connection removal. I therefore have to do two round-trips: check if the connection exists and then proceed with the original operation.

Here’s an example of how that could be implemented:

const post = ctx.db.query.post({ where: { args.id } });
const exists = post.user ? true : false;

// A. Net-new-connection
if (args.user && !exists) {
   args.user = { connect: { id } }
}

// B. Replacement-connection
// This is the method you described in your reply. I could combine with A block above.
if (args.user && exists) {
   args.user = { connect: { id } }
}

// C. Remove Connection
if (!args.user && exists) {
   args.user = { disconnect: true }
}

Let me know if this is overkill. I would prefer to not two round-trips to the db!


#4

Your solution looks pretty good to me.
As both A and B perform the same action I would change it to:

//A
    if (args.user) {
      args.user = { connect: { id } }
    }

//B
    if (!args.user && exists) {
          args.user = { disconnect: { id } }
        }

Maybe look into the ‘check existence’ Prisma offers. I use it to check whether the user is the author of a post and therefore can update the post for example. This will return a Boolean value instead of the whole post. So it would look something like this:

      const authorExists = await prisma.exists.Post({
        author: {
        id: not_null
        }
       });

#5

Thanks for the tip re: exists! Had no idea this was part of Prisma’s API.

One quick follow-up re: client. I’m having to do quite similar logic in my Apollo client for the optimistic update to match the mutation. Currently I update up to 3 fragments: update the post field on the User type, and then update the user field on the disconnected Post, and finally update the user field on the newly-connected Post.

I have not gotten this to work in one elegant update where I just update the Post, and the then the Users update their relations as well. Curious if you have some pointers there.


#6

This topic was automatically closed 45 days after the last reply. New replies are no longer allowed.