배열 형태로 저장된 로그 중에서 특정 단어가 포함된 항목만 골라내고 싶다면 aggregate()와 $filter 연산자를 함께 사용하면 됩니다. 이 글에서는 "work"라는 단어가 들어간 로그만 필터링하는 방법을 예제와 함께 단계별로 살펴보겠습니다.
1. 테스트용 컬렉션 생성
먼저 insertOne() 메서드를 사용해 샘플 문서가 담긴 컬렉션을 만듭니다. 여기서는 서버 이름과 상태 로그 배열을 가진 문서를 하나 삽입합니다.
> db.demo383.insertOne(
... {
... "ServerName":"Jboss",
... "ServerLogs": [
... {
... "status":"Working"
... },
... {
... "status":"Stop"
... },
... {
... "status":"Worked"
... }
... ]
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e5b635422064be7ab44e7f1")
}
2. 저장된 문서 확인하기
find() 메서드로 컬렉션의 모든 문서를 조회해 데이터가 정상적으로 들어갔는지 확인합니다.
> db.demo383.find().pretty();
위 명령을 실행하면 다음과 같은 결과가 출력됩니다.
{
"_id" : ObjectId("5e5b635422064be7ab44e7f1"),
"ServerName" : "Jboss",
"ServerLogs" : [
{
"status" : "Working"
},
{
"status" : "Stop"
},
{
"status" : "Worked"
}
]
}
3. 'work'가 포함된 로그만 필터링하는 쿼리
이제 집계 파이프라인에서 $addFields로 ServerLogs 필드를 새로 정의하고, 그 안에서 $filter를 적용합니다. 조건식(cond)에는 $indexOfBytes와 $toUpper를 조합했는데, 두 값을 모두 대문자로 변환해 비교하기 때문에 대소문자 구분 없이 "work"가 포함된 요소만 남게 됩니다.
$indexOfBytes는 검색 문자열을 찾지 못하면 -1을 반환하므로, 결과가 -1이 아닌 경우($ne)만 통과시키는 방식으로 동작합니다.
> db.demo383.aggregate([
... { "$addFields": {
... "ServerLogs": {
... "$filter": {
... "input": "$ServerLogs",
... "cond": {
... "$ne": [
... { "$indexOfBytes": [
... { "$toUpper": "$$this.status" },
... { "$toUpper": "work" }
... ]},
... -1
... ]
... }
... }
... }
... }}
... ])
4. 실행 결과
쿼리를 실행하면 "Working"과 "Worked"처럼 "work"가 포함된 로그만 남고, 해당 단어가 없는 "Stop"은 제외된 것을 확인할 수 있습니다.
{
"_id" : ObjectId("5e5b635422064be7ab44e7f1"), "ServerName" : "Jboss", "ServerLogs" : [
{ "status" : "Working" }, { "status" : "Worked" }
]
}
이처럼 $filter와 $indexOfBytes, $toUpper를 조합하면 배열 내 문자열 부분 일치 검색도 간단하게 처리할 수 있습니다. 실무에서는 서버 로그 분석, 에러 메시지 검색 등 다양한 상황에서 유용하게 활용할 수 있습니다.