MongoDB에서 특정 필드의 값이 같은 문서 내 배열 필드에 포함되어 있는 경우, 해당 문서를 조회 결과에서 제외하고 싶을 때가 있습니다. 이럴 때는 $not 연산자와 $in 연산자를 함께 사용하면 됩니다.
예제 컬렉션 생성
먼저 실습에 사용할 컬렉션을 만들어 보겠습니다. 아래와 같이 두 개의 문서를 삽입합니다.
[
{
id: "101",
subjectid: [
"102"
]
},
{
id: "102",
subjectid: [
"102"
]
}
]위 데이터에서 주목할 점은 id가 "102"인 문서의 경우, 자신의 subjectid 배열 안에 "102"라는 값이 이미 들어 있다는 것입니다. 즉, 자기 자신의 id가 배열에 포함된 상황입니다.
저장된 문서 확인하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 확인할 수 있습니다.
db.collection.find()
위 쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
[
{
"_id": ObjectId("5a934e000102030405000000"),
"id": "101",
"subjectid": [
"102"
]
},
{
"_id": ObjectId("5a934e000102030405000001"),
"id": "102",
"subjectid": [
"102"
]
}
]$expr, $not, $in을 활용한 제외 쿼리
이제 핵심인 쿼리를 살펴보겠습니다. $expr 연산자를 사용하면 집계 표현식(aggregation expression)을 일반 find() 쿼리 안에서 사용할 수 있습니다. 여기에 $not으로 논리 부정을 적용하고, $in으로 id 값이 subjectid 배열에 존재하는지 검사합니다.
db.collection.find({
$expr: {
$not:{
$in: [
"$id",
"$subjectid"
]
}
}
})쿼리의 동작 원리를 단계별로 설명하면 다음과 같습니다.
$in: ["$id", "$subjectid"]— 각 문서에서id필드의 값이subjectid배열에 포함되어 있는지 판별합니다.$not— 위 조건의 결과를 반전시켜, id가 배열에 포함되어 있지 않은 문서만 통과시킵니다.$expr— 필드 간 비교가 필요한 경우에 사용하는 연산자로, 문자열이 아닌 필드 값을 참조할 때 앞에$를 붙입니다.
실행 결과
위 쿼리를 실행하면 다음과 같은 출력을 얻을 수 있습니다.
[
{
"_id": ObjectId("5a934e000102030405000000"),
"id": "101",
"subjectid": [
"102"
]
}
]결과를 보면 id가 "101"인 문서만 반환되었습니다. "102" 문서는 자신의 subjectid 배열에 "102"가 포함되어 있어 조건에 걸려 제외된 것입니다. 이처럼 $expr + $not + $in 조합을 사용하면 문서 내부의 필드와 배열 값을 비교하여 원하지 않는 문서를 손쉽게 필터링할 수 있습니다.