MongoDB에서 배열에 특정 값이 존재하는지 확인하고 부울 값으로 반환하기
배열 필드에 지정한 값이 포함되어 있으면 반환되는 객체에 true 부울 필드를 추가하고, 값이 NULL이거나 일치하는 값이 없으면 false를 설정하는 방법을 소개합니다. MongoDB의 집계(aggregation) 파이프라인과 $ifNull, $setIntersection 연산자를 활용하면 손쉽게 구현할 수 있습니다.
$ifNull 연산자의 역할
핵심은 $ifNull 연산자입니다. $ifNull은 표현식을 평가한 뒤, 그 결과가 null이 아니면 표현식의 값을 그대로 반환합니다. 덕분에 배열 필드가 null이거나 아예 존재하지 않는 문서도 오류 없이 안전하게 처리할 수 있습니다.
1단계: 샘플 컬렉션 생성
먼저 테스트에 사용할 컬렉션과 문서를 생성해 보겠습니다. 이름 배열이 있는 문서, null 값이 있는 문서, 해당 필드 자체가 없는 문서 등 다양한 경우를 모두 포함시켰습니다.
> db.demo542.insertOne({"ListOfName":["Chris","David"]});{
"acknowledged" : true,
"insertedId" : ObjectId("5e8cabc6ef4dcbee04fbbc17")
}
> db.demo542.insertOne({"ListOfName":null});{
"acknowledged" : true,
"insertedId" : ObjectId("5e8cabc8ef4dcbee04fbbc18")
}
> db.demo542.insertOne({"ListOfName":["David"]});{
"acknowledged" : true,
"insertedId" : ObjectId("5e8cabd3ef4dcbee04fbbc19")
}
> db.demo542.insertOne({"Name":"John"});{
"acknowledged" : true,
"insertedId" : ObjectId("5e8cabdaef4dcbee04fbbc1a")
}
2단계: find() 메서드로 전체 문서 조회
find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 확인할 수 있습니다.
> db.demo542.find();
위 명령을 실행하면 다음과 같은 출력 결과를 얻습니다.
{ "_id" : ObjectId("5e8cabc6ef4dcbee04fbbc17"), "ListOfName" : [ "Chris", "David" ] }
{ "_id" : ObjectId("5e8cabc8ef4dcbee04fbbc18"), "ListOfName" : null }
{ "_id" : ObjectId("5e8cabd3ef4dcbee04fbbc19"), "ListOfName" : [ "David" ] }
{ "_id" : ObjectId("5e8cabdaef4dcbee04fbbc1a"), "Name" : "John" }
3단계: 특정 값 존재 여부를 확인하는 집계 쿼리
다음은 변수 id에 담긴 값(여기서는 David)이 ListOfName 배열에 존재하는지 검사하는 쿼리입니다.
> var id = "David";
> db.demo542.aggregate([
... {
... "$project": {
... "matched": {
... "$eq": [
... {
... "$size": {
... "$ifNull": [
... { "$setIntersection": [ "$ListOfName", [id] ] },
... []
... ]
... }
... },
... 1
... ]
... }
... }
... }
... ])
쿼리의 동작 원리를 간단히 정리하면 다음과 같습니다.
$setIntersection: ListOfName 배열과 [id] 배열의 교집합을 구합니다. 값이 존재하면 해당 요소가 담긴 배열, 존재하지 않으면 빈 배열이 됩니다.$ifNull: 필드가 null이면 빈 배열([])로 대체하여 오류 발생을 방지합니다.$size: 교집합 배열의 길이를 계산합니다.$eq: 계산된 길이가 1이면 true, 그렇지 않으면 false를 matched 필드에 저장합니다.
쿼리 실행 결과는 다음과 같습니다.
{ "_id" : ObjectId("5e8cabc6ef4dcbee04fbbc17"), "matched" : true }
{ "_id" : ObjectId("5e8cabc8ef4dcbee04fbbc18"), "matched" : false }
{ "_id" : ObjectId("5e8cabd3ef4dcbee04fbbc19"), "matched" : true }
{ "_id" : ObjectId("5e8cabdaef4dcbee04fbbc1a"), "matched" : false }
결과를 살펴보면 Chris와 David가 모두 포함된 첫 번째 문서, David만 포함된 세 번째 문서는 matched가 true로 반환되었습니다. 반면 ListOfName이 null인 두 번째 문서와 해당 필드 자체가 없는 네 번째 문서는 false로 반환된 것을 확인할 수 있습니다. 이처럼 $ifNull과 $setIntersection을 조합하면 null이나 누락된 필드가 있어도 안전하게 배열 내 값 존재 여부를 판별할 수 있습니다.