개요
MongoDB에서 하나의 도큐먼트에 포함된 객체 배열 안에서 서로 다른 객체의 속성 값을 비교해야 하는 경우가 있습니다. 이럴 때는 $let 연산자와 $indexOfArray 연산자를 함께 사용하면 간단하게 해결할 수 있습니다.
이 글에서는 예제 컬렉션을 만들고, 배열 내 특정 객체들을 찾아 그 속성 값을 비교하는 쿼리를 단계별로 살펴보겠습니다.
1. 컬렉션 생성 및 문서 삽입
먼저 insertOne() 메서드를 사용하여 샘플 문서가 담긴 컬렉션을 생성합니다.
> db.demo366.insertOne(
... {
... "Name" : "Chris",
... "details" : [
... {
... "Id" : "John1",
... "value" : "test"
... },
... {
... "Id" : "John2",
... "value" : 18
... },
... {
... "Id" : "John3",
... "value" : 20
... }
... ]}
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e57ddd92ae06a1609a00ae7")
}위 문서에는 details라는 객체 배열이 있으며, 각 객체는 Id와 value 필드를 가지고 있습니다.
2. 전체 문서 조회하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 확인할 수 있습니다.
> db.demo366.find();
실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e57ddd92ae06a1609a00ae7"), "Name" : "Chris", "details" : [
{ "Id" : "John1", "value" : "test" }, { "Id" : "John2", "value" : 18 },
{ "Id" : "John3", "value" : 20 }
]
}3. 배열 내 객체 속성 비교 쿼리 작성하기
다음은 MongoDB 객체 배열에서 서로 다른 객체의 속성을 비교하는 쿼리입니다. 여기서는 Id가 "John2"인 객체의 value와 "John3"인 객체의 value를 비교합니다.
> db.demo366.find(
... {"$expr":{
... "$let":{
... "vars":{
... "john2":{"$arrayElemAt":["$details",{"$indexOfArray":["$details.Id","John2"]}]},
... "john3":{"$arrayElemAt":["$details",{"$indexOfArray":["$details.Id","John3"]}]}
... },
... "in":{"$lt":["$$john2.value","$$john3.value"]}}
... }})실행 결과는 다음과 같습니다.
{
"_id" : ObjectId("5e57ddd92ae06a1609a00ae7"), "Name" : "Chris", "details" : [
{ "Id" : "John1", "value" : "test" }, { "Id" : "John2", "value" : 18 },
{ "Id" : "John3", "value" : 20 }
]
}"John2"의 value(18)가 "John3"의 value(20)보다 작기 때문에 조건을 만족하는 해당 문서가 결과로 반환되었습니다.
쿼리 동작 원리
- $expr: find() 쿼리 안에서 집계(aggregation) 표현식을 사용할 수 있도록 해줍니다.
- $let:
vars영역에서 변수를 정의하고,in영역에서 해당 변수를 활용한 표현식을 실행합니다. - $indexOfArray:
$details.Id배열에서 "John2", "John3"에 해당하는 요소의 인덱스 위치를 찾습니다. - $arrayElemAt: 찾은 인덱스를 이용해
details배열에서 해당 객체 전체를 추출합니다. - $lt: 두 변수(
$$john2.value,$$john3.value)의 값을 비교하여 앞의 값이 뒤의 값보다 작으면 true를 반환합니다.
마무리
이처럼 $let과 $indexOfArray를 조합하면 MongoDB 객체 배열 내부의 서로 다른 객체 속성을 자유롭게 비교할 수 있습니다. 이 기법은 배열 요소 간 조건 검색이 필요한 다양한 상황에서 유용하게 활용될 수 있습니다.