MongoDB에서 필드가 없는 문서에만 타임스탬프 추가하기
MongoDB에서 특정 필드가 존재하지 않는 문서에만 새로운 날짜 필드를 추가하고 싶다면 $exists 연산자와 함께 update() 메서드를 사용하면 됩니다. 이때 upsert와 multi 옵션의 역할을 정확히 이해하는 것이 중요합니다.
핵심 옵션: upsert와 multi
upsert 옵션
upsert를 true로 설정하면, 쿼리 조건과 일치하는 문서가 하나도 없을 때 새로운 문서를 자동으로 생성해 삽입합니다. 기본값은 false이며, 이 경우 일치하는 문서가 없더라도 새 문서를 삽입하지 않습니다.
multi 옵션
multi를 true로 설정하면 쿼리 조건을 충족하는 모든 문서를 한 번에 업데이트합니다. 반대로 false(기본값)로 설정하면 조건에 맞는 첫 번째 문서 하나만 업데이트됩니다.
예제 컬렉션 생성
먼저 실습용 컬렉션을 만들고 문서를 삽입해 보겠습니다. 일부 문서에는 DueDate 필드가 있고, 일부에는 없는 상태로 준비했습니다.
> db.demo479.insertOne({"DueDate":new ISODate("2020-01-10"),"Name":"Chris"});{
"acknowledged" : true,
"insertedId" : ObjectId("5e820733b0f3fa88e2279094")
}
> db.demo479.insertOne({"Name":"David"});{
"acknowledged" : true,
"insertedId" : ObjectId("5e820748b0f3fa88e2279095")
}
> db.demo479.insertOne({"DueDate":new ISODate("2019-12-31"),"Name":"Bob"});{
"acknowledged" : true,
"insertedId" : ObjectId("5e82075fb0f3fa88e2279096")
}
> db.demo479.insertOne({"Name":"Carol"});{
"acknowledged" : true,
"insertedId" : ObjectId("5e820767b0f3fa88e2279097")
}현재 문서 조회하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 확인할 수 있습니다.
> db.demo479.find();
실행 결과는 다음과 같습니다.
{ "_id" : ObjectId("5e820733b0f3fa88e2279094"), "DueDate" : ISODate("2020-01-10T00:00:00Z"), "Name" : "Chris" }
{ "_id" : ObjectId("5e820748b0f3fa88e2279095"), "Name" : "David" }
{ "_id" : ObjectId("5e82075fb0f3fa88e2279096"), "DueDate" : ISODate("2019-12-31T00:00:00Z"), "Name" : "Bob" }
{ "_id" : ObjectId("5e820767b0f3fa88e2279097"), "Name" : "Carol" }David와 Carol 문서에는 DueDate 필드가 없는 것을 확인할 수 있습니다.
타임스탬프 필드가 없는 경우에만 추가하는 쿼리
아래 쿼리는 DueDate 필드가 존재하지 않는 문서에만 현재 시각(new Date)을 값으로 갖는 DueDate 필드를 추가합니다.
> db.demo479.update({DueDate:{$exists:false}}, {$set : {"DueDate":new Date}}, {upsert:false, multi:true});
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })쿼리 분석:
{DueDate:{$exists:false}}: DueDate 필드가 없는 문서만 선택합니다.{$set : {"DueDate":new Date}}: 선택된 문서에 현재 시각으로 DueDate 필드를 설정합니다.{upsert:false, multi:true}: 새 문서를 생성하지 않고, 조건에 맞는 모든 문서를 업데이트합니다.
업데이트 결과 확인
다시 find() 메서드로 전체 문서를 조회해 보겠습니다.
> db.demo479.find();
실행 결과는 다음과 같습니다.
{ "_id" : ObjectId("5e820733b0f3fa88e2279094"), "DueDate" : ISODate("2020-01-10T00:00:00Z"), "Name" : "Chris" }
{ "_id" : ObjectId("5e820748b0f3fa88e2279095"), "Name" : "David", "DueDate" : ISODate("2020-03-30T14:52:29.656Z") }
{ "_id" : ObjectId("5e82075fb0f3fa88e2279096"), "DueDate" : ISODate("2019-12-31T00:00:00Z"), "Name" : "Bob" }
{ "_id" : ObjectId("5e820767b0f3fa88e2279097"), "Name" : "Carol", "DueDate" : ISODate("2020-03-30T14:52:29.656Z") }David와 Carol 문서에만 DueDate 필드가 새로 추가된 것을 확인할 수 있습니다. 이미 DueDate 필드가 있던 Chris와 Bob 문서는 원래 값이 그대로 유지됩니다.
참고: 최신 MongoDB 버전에서는 updateMany() 권장
MongoDB 4.2부터는 구식 update() 메서드 대신 updateMany() 또는 updateOne() 사용이 권장됩니다. 위와 동일한 작업은 다음과 같이 더 간결하게 작성할 수 있습니다.
db.demo479.updateMany({DueDate:{$exists:false}}, {$set : {"DueDate":new Date}});updateMany()는 기본적으로 multi:true처럼 동작하므로 별도의 multi 옵션을 지정할 필요가 없습니다.