$group에서 쓰던 이름이 $project에서도 지원되는 것은 아니다
사용자별 크레딧 사용량 API가 개발 서버에서 InvalidPipelineOperator(168), Unrecognized expression $first 오류로 실패했다. 변경 기록에 남은 문제는 사용자와 추가 할당량을 조인한 뒤 배열의 첫 원소를 꺼내는 표현식이었다. 운영 장애로 확인한 사례는 아니다.
$first는 쓰는 위치에 따라 다른 연산이다. $group의 누산기는 그룹에서 첫 문서의 값을 고르고, 배열 표현식은 한 문서의 배열에서 첫 원소를 고른다. 같은 이름의 누산기를 이미 사용하고 있다는 이유로 배열 표현식까지 지원된다고 볼 수는 없다. MongoDB 문서도 이 사용 맥락을 구분한다. 당시 소스와 회귀 테스트 주석은 배열 표현식이 4.4에서 추가됐으며 4.2 이하 개발 서버에서 실패했다고 기록한다.
인덱스 0을 읽고 빈 결과는 null로 돌려준다
조인 결과의 배열에서 첫 항목을 꺼내는 데 새로운 배열 표현식이 반드시 필요하지는 않았다. user_name, user_type, extra의 projection을 $arrayElemAt으로 바꾸고 바깥의 $ifNull은 유지했다. 아래는 이름 필드의 전후 비교다.
// 변경 전
user_name: { $ifNull: [{ $first: '$user.user_name' }, null] }
// 변경 후
user_name: { $ifNull: [{ $arrayElemAt: ['$user.user_name', 0] }, null] } $arrayElemAt은 지정한 인덱스의 원소를 반환한다. 인덱스 0으로 같은 첫 원소를 읽고, 조인 결과가 비어 값이 나오지 않는 경우는 기존처럼 null로 처리한다. 소스는 이 연산자의 지원 시작 버전을 3.2로 기록한다. 조인 대상과 응답 필드 구성을 바꿀 필요 없이 문제의 표현식만 교체했다.
서버 버전을 올려 기존 문법을 유지하는 방법도 있다. 다만 이 API의 오류를 해결하는 범위를 넘어 DB 업그레이드와 다른 쿼리의 호환성까지 확인해야 한다. 해당 수정은 출력 계약을 유지하면서 현재 서버가 이해하는 표현식으로 바꾸는 쪽을 택했다.
파이프라인 모양의 검증과 서버 실행 검증을 구분한다
회귀 테스트는 getUserUsage가 모킹한 aggregate에 넘긴 파이프라인에서 projection을 꺼낸다. 그 projection에 $first가 없는지, user_name과 extra가 정확히 $ifNull과 $arrayElemAt의 조합인지 단언한다. 필드 값만 검사하면 놓칠 수 있는 문법의 재도입을 막는 테스트다.
테스트 이름은 MongoDB 4.2 호환성을 말하지만 실제로 4.2 서버를 기동하지는 않는다. 모든 단계의 모든 연산자를 실행해 호환성을 증명하는 검사도 아니다. AI Chat / Tutor의 이 수정이 직접 고정한 범위는 문제가 된 projection 표현식과 기존 null 출력 계약이다.