본문 바로가기

백엔드/Prisma + GraphQL

Prisma2 데이터 모델링3 - Self Relation

테이블 내 두 개의 레코드를 1:1로 매칭시킵니다.

사용예(Usecase)

Following 시스템

schema.prisma

model User {
  id          Int       @default(autoincrement()) @id
  followers   User[]    @relation("UserFollows", references: [id])
  following   User[]    @relation("UserFollows", references: [id])
}

역시 Relation이기 때문에 컬럼이 생성되지 않습니다.

참조: Prisma2 데이터 모델링1 - 1:1 Relation

 

대신 Self Relation은 Relation에 사용된 심볼("UserFollows")에 언더바(_)가 추가된 Relation 테이블이 데이터베이스에 생성됩니다.

User 레코드와 _UserFollows 레코드 관계 _UserFollows 생성식

참고: Prisma2 CLI를 사용하여 데이터베이스 테이블 생성

 

User1이 자신의 following 배열에 User2.id를 넣으면, Relation에 의해 _UserFolows 테이블에 A컬럼B 컬럼이 각각 User1.idUser2.id인 레코드가 생성되고, User2의 followers에 User1.id가 자동으로 추가됩니다.

이러한 Self Relation 덕분에 Following 시스템을 코드 몇 줄로 구현할 수 있습니다.

다음은 Following 상태를 토글하는 Resolver의 일부입니다.

toggleFollow.js

// User1의 Following에 User2의 id가 있는지 검색
const alreadyFollowing = (await (await prisma.user.findOne({
    where: {id: user1.id},
    include: { following: true }
}))
.following
.map(user => user.id))
.includes(user2.id)

// 팔로잉 (alreadyFollowing == false)
prisma.user.update({ // 3. 변경(update)을 한다.
    where: { id: user1.id }, // 1. id가 user1.id인 User를 찾아서
    data: {
        following: {
            connect: {
                user2.id // 2. following에 user2.id를 추가(connect)하는
            }
        }
    },
    include: { following: true }
})

// 언팔로잉 (alreadyFollowing == true)
prisma.user.update({ // 3. 변경(update)을 한다.
    where: { id: user1.id }, // 1. id가 user1.id인 User를 찾아서
    data: {
        following: {
            disconnect: {
                user2.id // 2. following에 user2.id를 삭제(disconnect)하는
            }
        }
    },
    include: { following: true }
})

참고로 Relation이 되어있기 때문에, 만약 User1가 삭제된다면, _UserFollows에서 컬럼에 User1.id가 있는 모든 레코드까지 같이 삭제됩니다.

출처: https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/relations#self-relations