Spring Data MongoDB의 `AddFieldsOperationBuilder`

Mando·2025년 5월 4일
2

오픈소스

목록 보기
2/3

처음엔 그냥 정렬하려고 했다

회사 일을 하는 중 발생한 과정으로 적당한 상황 예시를 들자면
MongoDB Aggregation 파이프라인에서
bar 필드의 값을 foo라는 새로운 필드로 복사하고, 그걸 기준으로 정렬하려고 했다.

Spring Data MongoDB로는 이렇게 작성했다:

AggregationOperation addFields = addFieldWithValueOf("foo", "bar");
AggregationOperation sort = sort(Direction.DESC, "foo");

단순한 의도였다.


그런데 정렬이 안 됐다

쿼리는 잘 나갔고, 에러도 안 났다.
그런데 결과 정렬이 엉망이었다.
중간에 생성된 쿼리를 확인해보니, 예상했던 쿼리와 달랐다.

내가 기대한 쿼리:

{
  "$addFields": {
    "foo": "$bar"
  }
}

실제 생성된 쿼리:

{
  "$addFields": {
    "foo": {
      "bar": 1
    }
  }
}

$bar가 아니라 { bar: 1 }이라는 객체가 들어가 있었다.
MongoDB는 이걸 객체로 인식해 foo 필드에 넣은 것이고, 당연히 정렬이 안 되는 게 맞았다.


에러가 안 나서 더 위험했다

이 문제가 특히 심각한 이유는 MongoDB가 에러를 안 낸다는 점이다.
문법적으로는 유효한 BSON이기 때문에
에러 없이 실행되지만, 결과는 완전히 잘못된다.


그래서 파고들어봤다

내부 구현 코드를 보면 문제는 이 한 줄에서 비롯됐다:

valueMap.put(field, value instanceof String stringValue ? Fields.fields(stringValue) : value);

여기서 "bar"는 단일 필드명인데, Fields.fields(...)로 감싸면서
MongoDB가 객체로 해석하게 만들어버렸다.

해결책은 단순했다 — 단일 필드 참조는 Fields.field(...)로 감싸야 했다:

- Fields.fields("bar")
+ Fields.field("bar")

그래서 이 문제를 수정한 PR을 올리고자 했고,
실제로 #4933 이슈가 이미 존재해서 이를 바탕으로 PR을 해결하게 됐다.


더 큰 문제는 여기서 끝나지 않는다는 것

이 문제는 단순히 정렬뿐 아니라, 다른 파이프라인 연산에서도 발생할 수 있었다.
예를 들어 다음과 같은 연산들도 모두 오작동할 수 있었다:


❌ 조건 비교 실패

{
  "$match": {
    "foo": { "$gt": 100 }
  }
}

foo{bar: 1}이라는 객체이면, 숫자 비교 불가


❌ 산술 연산 실패

{
  "$project": {
    "result": { "$add": ["$foo", 5] }
  }
}

foo가 숫자일 줄 알았는데 객체면, $add에서 런타임 에러 발생


정리

이 문제는 단순히 "문자열로 넘긴 필드명이 잘못 해석됨" 같은 사소한 버그처럼 보이지만,
실제로는 MongoDB 파이프라인 전반에 걸쳐 영향을 미치는 치명적인 구조적 버그였다.

  • 잘못된 BSON 문서를 생성하고
  • 에러 없이 실행되며
  • 결과를 왜곡시키고
  • 디버깅을 어렵게 만들고
  • 후속 연산들을 연쇄적으로 오작동시킴

이런 과정을 직접 겪고 파고들면서
Spring Data MongoDB에 PR을 올려 메인 컨테이너의 답변까지는 받은 상황이다.


한줄 회고

단순히 정렬이 안 되던 작은 의심이,
라이브러리의 오픈소스 기여로 이어졌다.
머지되면 좋겠다......

1개의 댓글

comment-user-thumbnail
어제

너무 멋져요

답글 달기