MongoDB에서 배열 내부에 동일한 값이 두 번 이상 포함된 문서를 찾으려면 $where 연산자와 자바스크립트 스크립트를 함께 사용하면 됩니다. $where 연산자는 각 문서에 대해 자바스크립트 함수를 실행하여 조건을 평가할 수 있게 해주므로, 배열 요소를 순회하며 개수를 세는 로직을 구현할 수 있습니다.
1. 샘플 컬렉션 생성
먼저 예제로 사용할 컬렉션을 만들고 문서를 삽입해 보겠습니다. 가격 정보를 담은 ListOfPrice 배열을 포함하는 두 개의 문서를 생성합니다.
> db.sameValueMultipleTimesDemo.insertOne(
{
"ListOfPrice":[
{"Price": 110},
{"Price": 130},
{"Price": 145}
]
}
);
{
"acknowledged" : true,
"insertedId" : ObjectId("5cefc4e6ef71edecf6a1f6b9")
}
> db.sameValueMultipleTimesDemo.insertOne(
{
"ListOfPrice":[
{"Price": 110},
{"Price": 178},
{"Price": 110}
]
}
);
{
"acknowledged" : true,
"insertedId" : ObjectId("5cefc4e7ef71edecf6a1f6ba")
}위 예제에서 첫 번째 문서의 배열에는 서로 다른 가격(110, 130, 145)이 들어 있고, 두 번째 문서에는 110이 두 번 반복되어 있습니다.
2. 전체 문서 조회하기
find() 메서드를 사용해 컬렉션의 모든 문서를 확인합니다.
> db.sameValueMultipleTimesDemo.find().pretty();
출력 결과
{
"_id" : ObjectId("5cefc4e6ef71edecf6a1f6b9"),
"ListOfPrice" : [
{
"Price" : 110
},
{
"Price" : 130
},
{
"Price" : 145
}
]
}
{
"_id" : ObjectId("5cefc4e7ef71edecf6a1f6ba"),
"ListOfPrice" : [
{
"Price" : 110
},
{
"Price" : 178
},
{
"Price" : 110
}
]
}3. $where 연산자로 중복 값 찾기
이제 배열에서 특정 값(여기서는 110)이 여러 번 등장하는 문서만 조회하는 쿼리입니다. filter() 메서드로 조건에 맞는 요소의 개수를 세어 1보다 큰지 검사합니다.
> db.sameValueMultipleTimesDemo.find({
"$where": function() {
return this.ListOfPrice.filter(function(p) {
return p.Price == 110;
}).length > 1;
}
})출력 결과
{ "_id" : ObjectId("5cefc4e7ef71edecf6a1f6ba"), "ListOfPrice" : [ { "Price" : 110 }, { "Price" : 178 }, { "Price" : 110 } ] }결과를 보면 Price가 110인 요소가 두 개 포함된 두 번째 문서만 반환된 것을 확인할 수 있습니다.
참고 사항
$where 연산자는 자바스크립트를 실행하기 때문에 인덱스를 활용하지 못하고 성능이 떨어질 수 있습니다. 따라서 대량의 데이터를 다루는 운영 환경에서는 집계 파이프라인($unwind, $group 등)을 활용한 대안을 먼저 고려하는 것이 좋습니다. 다만 소규모 데이터나 임시 조회 작업에서는 위 예제처럼 $where가 간편하고 직관적인 해결책이 됩니다.