MongoDB에서 배열 안에 포함된 하위 문서를 다룰 때, 특정 키의 값이 주어진 값과 일치하는 요소만 찾아 그 위치에 있는 다른 키의 값을 수정해야 하는 경우가 자주 있습니다. 이럴 때는 쿼리 조건에 $elemMatch 연산자를 사용하고, 업데이트 시에는 위치 연산자 $를 활용하면 간단하게 해결할 수 있습니다.
1. 샘플 컬렉션 생성하기
먼저 실습에 사용할 문서를 담은 컬렉션을 생성해 보겠습니다.
> db.demo196.insertOne(
... {
... "Id" : "101",
... "details" : [
... {
... "FirstName" : "Chris",
... "LastName" : "Brown",
... "Score" : 45
... },
... {
... "FirstName" : "David",
... "LastName" : "Miller",
... "Score" : 87
... },
... {
... "FirstName" : "John",
... "LastName" : "Doe",
... "Score" : 56
... }
... ]
... }
...);
{
"acknowledged" : true,
"insertedId" : ObjectId("5e3af6b103d395bdc21346d7")
}2. 저장된 문서 확인하기
find() 메서드를 사용하여 컬렉션의 모든 문서를 조회합니다.
> db.demo196.find();
위 명령을 실행하면 다음과 같은 결과가 출력됩니다.
{
"_id" : ObjectId("5e3af6b103d395bdc21346d7"), "Id" : "101", "details" : [
{ "FirstName" : "Chris", "LastName" : "Brown", "Score" : 45 },
{ "FirstName" : "David", "LastName" : "Miller", "Score" : 87 },
{ "FirstName" : "John", "LastName" : "Doe", "Score" : 56 }
]
}3. 조건에 맞는 배열 요소 업데이트하기
이제 핵심 부분입니다. 아래 쿼리는 FirstName이 "David"이고 LastName이 "Miller"인 배열 요소를 찾아, 해당 요소의 Score 값을 98로 변경합니다.
> db.demo196.update({"details":{"$elemMatch":{"FirstName" : "David", "LastName" : "Miller"}}},
... {"$set":{"details.$.Score":98}});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })여기서 동작 원리를 살펴보면 다음과 같습니다.
- $elemMatch: details 배열 안에서 FirstName과 LastName 조건을 모두 만족하는 요소를 매칭합니다.
- details.$: 위치 연산자($)는 쿼리에서 매칭된 첫 번째 배열 요소의 인덱스를 가리키므로, $set이 정확히 해당 요소에만 적용됩니다.
4. 업데이트 결과 확인하기
다시 find() 메서드로 전체 문서를 조회하여 변경 사항을 확인합니다.
> db.demo196.find();
실행 결과 David Miller의 Score가 87에서 98로 정상적으로 변경된 것을 볼 수 있습니다.
{
"_id" : ObjectId("5e3af6b103d395bdc21346d7"), "Id" : "101", "details" : [
{ "FirstName" : "Chris", "LastName" : "Brown", "Score" : 45 },
{ "FirstName" : "David", "LastName" : "Miller", "Score" : 98 },
{ "FirstName" : "John", "LastName" : "Doe", "Score" : 56 }
]
}마무리
이처럼 MongoDB에서 배열 내부의 특정 요소를 조건 기반으로 업데이트할 때는 $elemMatch로 대상을 먼저 매칭하고, 위치 연산자 $를 통해 해당 요소의 필드만 선택적으로 수정하면 됩니다. 이 방식은 배열 크기가 크거나 여러 요소가 비슷한 구조를 가질 때 특히 유용하며, 불필요한 전체 배열 교체 없이 효율적으로 데이터를 간신할 수 있다는 장점이 있습니다.