저번 글에서 @ResolveField()
를 통해서 추가 필드값을 받고, 해당 필드를 구현하기 위해서 @ResolveReference()
로 받아서 로직을 처리하는 방법을 구현했었다.
해당 내용을 공부해보니,
"이렇게 하면 N+1 문제가 발생해서 DataLoader
를 사용하면 문제를 해결할 수 있다~"
라는 글을 많이 봤는데, N+1 문제로 인해 쿼리 지연이 발생하려면, resolveField 가 배열, 즉 여러 값이 나와야 그러한 문제가 발생할 수 있겠다~ 라고 생각해서, 저번에는 필드가 배열이 아닌 하나의 값으로 구현을 했는데 이번에는 배열로 한번 받아보자 라는 생각에 배열로 구현을 해보기로 했다.
그런데, 아무리 해도 계속 배열로 뭔가 받질 못하는 것 같아서 수 많은 구글링과 phind 및 gpt 를 찾아봐도 내가 원하는 결과를 도출해낼 수 없었다.
구현하고자 하는 내용을 말하자면, 하나의 채팅방에 여러명의 유저가 있을 수 있고, 그러한 유저들의 정보를 채팅방 정보와 같이 조회를 하기 위한 기능이었다.
그래서 근본적으로 생각을 해봤는데,
1. 일단 ! 필드 자체는 배열이긴 하다.(하나의 채팅방에 유저는 여러명이니까) 그러면 이 resolveReference 가 쿼리를 여러번 수신해야 하는건가?
👉 이건 아무리 생각해도 말이 안된다. 그래프큐엘을 만든 팀에서 과연 그렇게 비효율적으로 만들었을까
2. 그렇다면 일단 resolveField 는 배열을 반환하는 것은 맞다.
3. 그리고 이거를 resolveReference 도 결국에는 한번만 받고, 그 배열을 풀어내기 위한 로직을 여러번 하는건가
4. 이거다 !
결국에 구현해냈다. 물론 디비를 연결해서 실제로 데이터 커넥션을 일으킨건 아니지만, 전체적인 흐름을 파악할 수 있게 되었다.
/// chat.resolver.ts
@ResolveField('users', () => [AccountModel])
async getUsers(
@Parent() chat: RoomModel,
): Promise<{ __typename: string; id: number }[]> {
console.log(chat.roomId);
const userIds: number[] = [1, 2, 3];
return [
{ __typename: 'RoomModel', id: userIds[0] },
{ __typename: 'RoomModel', id: userIds[1] },
{ __typename: 'RoomModel', id: userIds[2] },
];
}
특정 채팅방의 roomId 를 이용해서 디비에서 조회를 한 후, 해당 채팅방에 존재 하는 유저들의 id 가 1,2,3 이라고 하자.
이 유저들의 정보를 chat.resolver
에서 조회하는 것이 아닌, account.resolver
에서 조회하기 때문에, account.resolver
쪽으로 array object 을 보내준다.
@ResolveReference()
resolveReference(reference: {
__typename: string;
id: string;
}): AccountModel {
return {
id: reference.id,
name: `${reference.id} + name`,
};
}
그러면 여기서 받아서 처리를 해주는데, 배열안에 아이템이 3개가 있기 때문에, @ResolveReference
를 3번 처리해줘야 한다.
이렇게 하나를 처리하기 위해 여러번의 쿼리를 실행할 경우 N+1 문제가 발생할 수 있다.