MongoDB에서 $regex는 기본적으로 정적 문자열이나 정규식 리터럴만 받을 수 있기 때문에, 다른 필드의 값을 직접 패턴으로 참조할 수 없습니다. 하지만 집계 파이프라인에서 $expr과 함께 $indexOfCP 연산자를 활용하면 이러한 제한을 우회할 수 있습니다. 이 글에서는 실제 예제를 통해 그 방법을 살펴보겠습니다.
테스트 데이터 생성하기
먼저 예제 문서들을 담은 컬렉션을 생성해 보겠습니다.
> db.demo88.insertOne(
... {
... "Name": "Chris",
... "PassoutYear": "2020",
... "websiteName": "chris.shop.com/Carol-2020-"
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e2c14c471bf0181ecc422b1")
}
> db.demo88.insertOne(
... {
... "Name": "David",
... "PassoutYear": "2010",
... "websiteName": "david.bigshop.com/David-2010-"
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e2c14c571bf0181ecc422b2")
}
여기서 주목할 점은 첫 번째 문서입니다. 이름(Name)은 “Chris”인데, 반면 websiteName 필드에는 “Carol”이라는 다른 이름이 들어 있습니다. 이 차이가 뒤에서 중요한 역할을 합니다.
저장된 문서 확인하기
find() 메서드를 사용해 컬렉션의 전체 문서를 조회합니다.
> db.demo88.find();
실행하면 다음과 같은 결과가 출력됩니다.
{ "_id" : ObjectId("5e2c14c471bf0181ecc422b1"), "Name" : "Chris", "PassoutYear" : "2020", "websiteName" : "chris.shop.com/Carol-2020-" }
{ "_id" : ObjectId("5e2c14c571bf0181ecc422b2"), "Name" : "David", "PassoutYear" : "2010", "websiteName" : "david.bigshop.com/David-2010-" }
$indexOfCP로 필드 값을 패턴처럼 매칭하기
다음 쿼리는 $indexOfCP를 사용해 Name 필드의 값이 websiteName 필드 안에 포함되어 있는지 확인합니다.
> db.demo88.aggregate([ { "$match": { "$expr": { "$ne": [ { "$indexOfCP": ["$websiteName", "$Name"] }, -1 ] } }} ])
실행 결과는 다음과 같습니다.
{ "_id" : ObjectId("5e2c14c571bf0181ecc422b2"), "Name" : "David", "PassoutYear" : "2010", "websiteName" : "david.bigshop.com/David-2010-" }
쿼리 동작 원리
이 쿼리가 의도한 대로 작동하는 이유는 다음과 같습니다.
- $indexOfCP는 두 번째 인자(여기서는
$Name값)가 첫 번째 인자($websiteName값) 내에서 처음 등장하는 위치를 UTF-8 코드 포인트 단위로 반환합니다. - 값이 발견되지 않으면 -1을 반환합니다.
- 따라서 결과가 -1이 아닌지(
$ne) 검사하면, 특정 필드의 값이 다른 필드에 포함된 문서만 필터링할 수 있습니다.
실제로 “David”의 경우 websiteName에 자신의 이름이 포함되어 있어 조회되었고, “Chris”는 websiteName에 “Chris”가 아닌 “Carol”이 들어 있어 결과에서 제외되었습니다.
참고 사항
$indexOfCP는 코드 포인트 단위로 위치를 계산합니다. 바이트 단위 계산이 필요하다면$indexOfBytes를 사용하세요.- 이 방식은 대소문자를 구분하는 정확한 부분 문자열 일치입니다. 복잡한 정규식 패턴이 필요하다면 애플리케이션 레벨에서 처리하는 것이 좋습니다.
$expr과$match의 조합은 일반적인 인덱스를 효율적으로 활용하지 못할 수 있으므로, 대용량 데이터에서는 성능을 미리 테스트하는 것이 권장됩니다.