MongoDB에서 여러 문서를 한 번에 Upsert하기
MongoDB에서 다수의 문서를 업서트(Upsert)하려면 개별적으로 updateOne()을 반복 호출하는 것보다 벌크(Bulk) 연산을 사용하는 것이 효율적입니다. 컬렉션에 대해 initializeUnorderedBulkOp()로 벌크 작업을 초기화한 뒤, find() 조건과 upsert(), update() 메서드를 체이닝하면 됩니다.
업서트란 '조건에 일치하는 문서가 존재하면 갱신(update)하고, 존재하지 않으면 새로 삽입(insert)한다'는 의미로, 데이터 동기화나 마이그레이션 작업에서 자주 활용됩니다. 아래 예제를 통해 전체 과정을 단계별로 살펴보겠습니다.
1단계: 컬렉션 생성 및 문서 삽입
먼저 demo425 컬렉션을 만들고 문서들을 삽입합니다.
> db.demo425.insertOne({"Name":"Chris","Age":21});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e74ee4fbbc41e36cc3cae6c")
}
> db.demo425.insertOne({"Name":"David","Age":23});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e74ee56bbc41e36cc3cae6d")
}
> db.demo425.insertOne({"Name":"Chris","Age":21});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e74ee57bbc41e36cc3cae6e")
}
> db.demo425.insertOne({"Name":"Chris","Age":21});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e74ee5cbbc41e36cc3cae6f")
}2단계: 삽입된 문서 확인
find() 메서드를 사용해 컬렉션의 모든 문서를 조회합니다.
> db.demo425.find();
위 명령은 다음과 같은 출력을 반환합니다.
{ "_id" : ObjectId("5e74ee4fbbc41e36cc3cae6c"), "Name" : "Chris", "Age" : 21 }
{ "_id" : ObjectId("5e74ee56bbc41e36cc3cae6d"), "Name" : "David", "Age" : 23 }
{ "_id" : ObjectId("5e74ee57bbc41e36cc3cae6e"), "Name" : "Chris", "Age" : 21 }
{ "_id" : ObjectId("5e74ee5cbbc41e36cc3cae6f"), "Name" : "Chris", "Age" : 21 }현재 'Chris'라는 이름을 가진 문서가 총 3개 존재합니다.
3단계: 벌크 연산으로 다중 문서 Upsert 실행
다음은 MongoDB에서 여러 문서를 한 번에 업서트하는 쿼리입니다.
> var b1 = db.demo425.initializeUnorderedBulkOp();
> b1.find( { Name: "Chris" } ).upsert().update(
... {
... $setOnInsert: { id:101},
... $set: { Name: "Robert", Age:23 }
... }
... );
> b1.execute();
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 0,
"nUpserted" : 0,
"nMatched" : 3,
"nModified" : 3,
"nRemoved" : 0,
"upserted" : [ ]
})여기서 주목할 부분은 두 가지입니다. 첫째, $setOnInsert는 새 문서가 삽입될 때만 적용되는 필드를 지정하므로, 이미 존재하는 문서에는 영향을 주지 않습니다. 둘째, $set은 조건에 일치하는 기존 문서의 값을 갱신합니다.
실행 결과에서 nMatched: 3, nModified: 3을 확인할 수 있는데, 이는 'Chris'라는 이름을 가진 3개의 기존 문서가 모두 찾아져 갱신되었음을 의미합니다. 조건에 일치하는 문서가 없었다면 nUpserted 값이 증가하며 새 문서가 삽입되었을 것입니다.
4단계: 최종 결과 검증
find() 메서드로 변경된 컬렉션을 다시 조회합니다.
> db.demo425.find();
실행 결과는 다음과 같습니다.
{ "_id" : ObjectId("5e74ee4fbbc41e36cc3cae6c"), "Name" : "Robert", "Age" : 23 }
{ "_id" : ObjectId("5e74ee56bbc41e36cc3cae6d"), "Name" : "David", "Age" : 23 }
{ "_id" : ObjectId("5e74ee57bbc41e36cc3cae6e"), "Name" : "Robert", "Age" : 23 }
{ "_id" : ObjectId("5e74ee5cbbc41e36cc3cae6f"), "Name" : "Robert", "Age" : 23 }'Chris'였던 3개 문서가 모두 'Robert'(나이 23)로 성공적으로 갱신되었고, 'David' 문서는 그대로 유지된 것을 확인할 수 있습니다.
정리
MongoDB에서 대량의 문서를 업서트할 때는 initializeUnorderedBulkOp()로 벌크 작업 객체를 만들고, find() → upsert() → update() 순서로 체이닝한 후 execute()로 실행하면 됩니다. 이 방식은 네트워크 왕복 횟수를 줄여 개별 업데이트보다 훨씬 빠른 성능을 제공하며, 대용량 데이터 일괄 처리에 특히 유용합니다.