💬 들어가며

최근 프로젝트를 하며 json 데이터를 DB 컬럼에 그대로 저장해야 할 상황이 많았다.

그동안 Nest.js TypeORM으로 json 데이터 타입을 다루는데 큰 문제가 없었는데
multipart/form-data로 넘어오는 json 데이터를 저장하며 문제가 발생했다.

 

개발 환경은 다음과 같다.

  • Nest.js + Typescript
  • TypeORM
  • PostgreSQL

 

🔥 문제

DB에 저장할 때 이런식으로 \n, \와 같은 개행문자가 들어가 있었다.

"[\n    {\n        \"index\": \"1\", ...생략]"

조회할 때도 정의된 Json 형식으로 매핑이 안되고 저 데이터 자체가 스트링으로 인식되어 통으로 매핑되었다.

 

  • 쿼리 매핑 결과
{
    "data": "[{\"index\": 1}, {\"index\": 2}]"
}

 

  • 원했던 결과
{
    "data": [
        {
            "index": 1
        },
        {
            "index": 2
        }
    ]
}

 

✔️ 원인

구글링을 열심히 했지만, 관련 자료가 많이 없었고
내 상황에는 다 적용이 되지 않아 이것저것 시도해보다가 방법을 찾았다.

 

insert 시 개행문자가 포함되는 이슈 - 발생 원인

우선 데이터 저장 시에 \n 이나 \가 저장되는 것은 일반적인 application/json 상황에는 발생하지 않았고 multipart/form-data로 넘어온 application/json 데이터 타입 상황에서만 발생했다.

 

뭔가 데이터 전송 방식에 따라 개행문자가 발생하는 것이 아닐까 생각한다.

 

select 시 json 객체로 매핑 안되는 이슈 - 발생 원인

multipart/form-data가 아닌 application/json으로 통신할 때는 조회 시에도 별 다른 문제가 없었다.

그런데 multipart/form-data 에서 파싱한 json 컬럼 데이터를 조회해 올 때는 문제가 발생했다.

(왜지? 어차피 DB에 들어가 있는 데이터를 조회하는데 네트워크 통신에서 발생하는 content-type과 상관이 있는게 이상하다.)

 

💣 해결

Entity 컬럼 정의 - jsonb

@Entity()
export class Entity {
  // ... 생략

  @Column({ type: 'jsonb', nullable: false, default: [] })
  data: object[]; // 그냥 object 했을 때도 문제 없었다.
}

typejson이나 jsonb 모두 잘 동작한다.

 

💡 참고:

공식 문서에 따르면 json, jsonb 두 타입의 차이는 다음과 같다.

Json Jsonb
데이터가 들어온 그대로 저장 문자열 사이의 공백 제거
(근데 나는 \ 엄청 들어오던데…)
key 순서 보장 O key 순서 보장 X
인덱싱 불가능 인덱싱 가능
  바이너리 포맷으로 저장됨
(바이너리 포맷이라 select 시에 json 매핑 이슈가 있었던 것일까…?)


예를 들면 아래와 같은 데이터가 있다고 할 때
Json은 순서가 그대로 DB에 들어가지만, Jsonbjob 다음에 name이 저장되기도 한다.

{
    "name": "jinny"
    "job": "backend-developer"
}

Service - 조회 로직

  • 처음에 JSON.parse(Json.stringify(entity.data))도 시도했지만 매핑이 안되었고 아래 처럼 코드를 바꾸어줬더니 해결되었다.
async findJsonEntity() {
    const entity: JsonEntity | null = await this.jsonEntityRepo.findOne({
      where: { id: BigInt(1) },
    });

    if (!entity) {
      throw new NotFoundException();
    }

    return { data: JSON.parse(entity.data as unknown as string) }; // 요렇게!!
  }

 

👋 마치며

nest.js는 구글링해도 정말 자료가 잘 안나와서, 영어로 구글링하는 것이 좋은 것 같다.
그나마 스택오버플로우에 질문을 보며 힌트를 얻을 때가 있는 것 같다.