MongoDB에서 데이터를 검색할 때, 특정 패턴과 일치하는 문자열을 찾기 위해 $regex
연산자를 사용합니다. 즉 find
나 aggregate
의 $match
연산자에서 사용하는 것이다.
MongoDB에서 $regex 연산자를 사용하는 주된 이유는 그 유연성과 강력한 패턴 매칭 능력 때문인데 복잡한 문자열 패턴을 검색하거나 부분 문자열을 찾는 데 매우 효과적이며, 대소문자 구분 옵션 등 다양한 검색 조건을 설정할 수 있다. 다만, $regex는 인덱스 사용에 제한이 있어 성능 저하가 발생할 수 있으므로, 대규모 데이터셋에서는 주의가 필요하다. 따라서, $regex는 정교한 문자열 검색이 필요한 상황에서 강력한 도구이지만, 성능과 사용 목적을 고려하여 적절히 활용하기 위해 관련 내용을 정리해본다.
$regex
사용법
MongoDB에서 $regex 연산자를 사용하는 것은 정규식 처리의 안전성과 일관성을 높이는 방법이다. JSON 호환성 문제를 해결하고, 문자열 이스케이프 관련 오류를 방지하며, 정규식 옵션을 명확히 지정할 수 있게 해준다. 예를 들어, db.collection.find({ name: { $regex: "pattern", $options: "i" } })
와 같이 사용하면, “pattern”이라는 정규식을 대소문자 구분 없이 검색할 수 있다. 이러한 방식은 MongoDB 쿼리에서 정규식을 더 안정적이고 효과적으로 활용할 수 있게 해준다.
// 예시: `typeArray.executeInfo.serviceType` 필드에 "api"를 포함하는 문서 검색
db.getCollection('intent_service_2').aggregate([
{
$match: {
'typeArray.executeInfo.serviceType': {
'$regex': 'api'
}
}
}
]);
$regex
구문 형식
{ <field>: { $regex: /pattern/, $options: '<options>' } }
{ <field>: { $regex: 'pattern', $options: '<options>' } }
{ <field>: { $regex: /pattern/<options> } }
예:
{ $regex: 'ttt' } // == /ttt/
$regex
활용 팁
- 복잡한 패턴: 메타 문자 (예: . ^ $ * + ? { } [ ] \ | ( ))를 사용하여 정교한 패턴을 정의할 수 있다.
- 옵션 사용:
i
(대소문자 무시),m
(다중 라인),s
(특수 문자 .이 모든 문자 일치) 등을 조합하여 검색 범위를 조절할 수 있다. - 한글 검색: 한글 정규 표현식을 사용할 경우 MongoDB 버전에 따라 처리 방식이 다를 수 있으므로 공식 문서를 참고.
MongoDB Unlike 검색
MongoDB에서는 특정 문자열을 포함하지 않는 문서를 검색할 수도 있습니다. 이를 위해 정규식을 활용하는데 내용은 다음과 같다.
패턴별 검색 예시
- 문자열을 포함하지 않는 문서 검색
db.collection.find({ name: { '$regex': '^((?!string).)*$', '$options': 'i' } });
- 대소문자 구분 없이 정확히 일치하는 문자열 검색
db.collection.find({ name: { '$regex': '^string$', '$options': 'i' } });
- 문자열로 시작하는 문서 검색
db.collection.find({ name: { '$regex': '^string', '$options': 'i' } });
- 문자열로 끝나는 문서 검색
db.collection.find({ name: { '$regex': 'string$', '$options': 'i' } });
- 문자열을 포함하는 문서 검색
db.collection.find({ name: { '$regex': 'string', '$options': 'i' } });
참고: StackOverflow MongoDB 검색 관련
MongoDB 필드명 변경
MongoDB에서 특정 필드명을 변경하려면 $rename
연산자를 사용한다. 아래 내용을 참고하시길 바란다.
$rename
사용법
// 조건에 따라 특정 필드명 변경
db.collection.update(
{ 조건 },
{
$rename: { "이전필드명": "변경할필드명" }
},
false, // upsert 옵션
true // multiple 옵션
);
$rename
활용 팁
- 배열 내 필드명 변경: 배열 내부의 필드명을 변경하려면 점 표기법을 사용하여 정확한 경로를 지정.
MongoDB 필드 삭제
필드 삭제를 위해 $unset
연산자를 사용할 수 있다. 이는 특정 조건에 따라 필드를 제거할 때 유용하다.
(다지우는게 아니다.)
$unset
사용법
- 모든 문서에서 특정 필드 삭제:
db.collection.update( {}, { $unset: { "삭제할필드명의Path": 1 } }, false, true );
- 조건에 따라 특정 필드 삭제:
db.collection.update( { '삭제할필드명의Path': { $exists: true } }, { $unset: { '삭제할필드명의Path': 1 } }, false, true );
배열 내 특정 필드 삭제
배열 내부의 필드를 삭제하려면 $exists
와 positional operator $
를 함께 사용할 수 있다.
db.collection.update(
{
'meta.asin': { $exists: true }
},
{
$unset: { 'meta.$.asin': true }
},
false,
true
);
주의: $unset
은 해당 필드만 삭제하고 다른 필드는 유지한다. 즉 선택적으로 삭제하는 것이다.
나는 개인적으로 혹여 unset으로 다 지워지지 않을까 싶어 테스트도 먼저 해봤다.
MongoDB Find 검색에서 $group
연산자 대체 projection
find
명령어는 $group
연산자를 지원하지 않아 당황스러웠다. 다만 projection을 활용하여 원하는 데이터를 추출할 수 있어 find 명령어를 쓸 때는 projection을 주로 사용했다.
MongoDB의 find 명령어는 $group 연산자를 지원하지 않지않는다 다소 당황스러웠다… 다만 projection 기능을 활용하면 원하는 필드만 선택적으로 추출할 수 있다.
예시
db.getCollection('intent_service_sub').find(
{ intent: 'WishBook_Applying_Guide' },
{
_id: 0,
intent: 1,
'intentArrayList.intent': 1,
'intentArrayList.sign': 1,
'intentArrayList.serviceType': 1
}
);
주의사항:
find
는 문서 단위로 조회하므로, 문서 틀 안에서 필드와 값을 변경할 수 있다.- 새로운 자료구조 형태나 복잡한 집계 작업이 필요하다면
aggregate
와 관련 연산자를 사용한다.
MongoDB 활용 사례
검색 기능 활용 시나리오
- 로그 데이터 검색: 특정 패턴의 로그 메시지를 찾아 문제를 진단
- 사용자 데이터 분석: 특정 조건을 만족하는 사용자를 찾아 분석
데이터 정제 및 변환
- 불필요한 필드 삭제:
$unset
을 이용하여 정리 - 필드명 변경:
$rename
을 통해 데이터 구조를 표준화
성능 최적화
- Projection 활용: 불필요한 필드를 제외하여 네트워크 트래픽을 줄이고 성능을 향상
- 인덱스 생성: 쿼리 성능 향상을 위해 적절한 인덱스를 설정
결론
MongoDB의 검색 기능은 유연하고 강력하여 다양한 데이터 분석 및 처리 작업에 활용될 수 있다.
$regex
, $unset
, $rename
, find
등의 기본적인 연산자를 숙달하고, 필요에 따라 고급 기능을 활용하면 더욱 효과적인 데이터 관리가 가능하니 MongoDB를 DB로 활용할 생각이 있다면 반드시 해당 연산자는 파악하시길 바란다.