MongoDB
대량 작업
수색…
비고
단일 콜렉션에 대해 대량으로 수행 할 쓰기 조작 목록 작성.
필드를 다른 유형으로 변환하고 전체 모음을 대량으로 업데이트
일반적으로 필드 유형을 다른 것으로 변경하려는 경우, 예를 들어 원래 컬렉션에 문자열로 저장된 "숫자"또는 "날짜"필드가있을 수 있습니다.
{
"name": "Alice",
"salary": "57871",
"dob": "1986-08-21"
},
{
"name": "Bob",
"salary": "48974",
"dob": "1990-11-04"
}
목표는 위와 같은 엄청난 컬렉션을 업데이트하는 것입니다.
{
"name": "Alice",
"salary": 57871,
"dob": ISODate("1986-08-21T00:00:00.000Z")
},
{
"name": "Bob",
"salary": 48974,
"dob": ISODate("1990-11-04T00:00:00.000Z")
}
상대적으로 작은 데이터의 경우, 커서의 forEach()
메소드를 사용하여 snapshot
을 사용하여 콜렉션을 반복하고 다음과 같이 각 문서를 업데이트함으로써 위의 사항을 달성 할 수 있습니다.
db.test.find({
"salary": { "$exists": true, "$type": 2 },
"dob": { "$exists": true, "$type": 2 }
}).snapshot().forEach(function(doc){
var newSalary = parseInt(doc.salary),
newDob = new ISODate(doc.dob);
db.test.updateOne(
{ "_id": doc._id },
{ "$set": { "salary": newSalary, "dob": newDob } }
);
});
작은 컬렉션의 경우에는 최적이지만 대용량 데이터 집합을 반복하고 서버에 대한 요청마다 각 업데이트 작업을 보내면 계산상의 불이익이 발생하므로 대규모 컬렉션의 성능이 크게 저하됩니다.
Bulk()
API는 쓰기 작업이 대량으로 한 번만 서버에 전송되기 때문에 구조 작업을 수행하고 성능을 크게 향상시킵니다. 이 메서드는 forEach()
루프 내의 현재 업데이트 문과 같이 서버에 모든 쓰기 요청을 보내지 않지만 1000 건의 요청마다 한 번만 수행하므로 현재보다 훨씬 효율적이고 신속한 업데이트가 가능하므로 효율성이 달성됩니다.
위의 동일한 개념을 forEach()
루프와 함께 사용하여 배치를 만들면 다음과 같이 대량으로 컬렉션을 업데이트 할 수 있습니다. 이 데모에서 MongoDB 버전 >= 2.6
및 < 3.2
에서 사용할 수있는 Bulk()
API는 initializeUnorderedBulkOp()
메소드를 사용하여 배치에서 쓰기 작업을 비 결정적 순서와 함께 병렬로 실행합니다.
salary
및 dob
필드를 각각 numerical
및 datetime
값으로 변경하여 clients 콜렉션의 모든 문서를 업데이트합니다.
var bulk = db.test.initializeUnorderedBulkOp(),
counter = 0; // counter to keep track of the batch update size
db.test.find({
"salary": { "$exists": true, "$type": 2 },
"dob": { "$exists": true, "$type": 2 }
}).snapshot().forEach(function(doc){
var newSalary = parseInt(doc.salary),
newDob = new ISODate(doc.dob);
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "salary": newSalary, "dob": newDob }
});
counter++; // increment counter
if (counter % 1000 == 0) {
bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
bulk = db.test.initializeUnorderedBulkOp();
}
});
다음 예제는 새로운 MongoDB 버전 3.2
적용됩니다.이 버전은 이후 Bulk()
API를 더 이상 사용하지 않으며 bulkWrite()
사용하여 더 새로운 apis 세트를 제공합니다.
위와 동일한 커서를 사용하지만 동일한 forEach()
커서 메서드를 사용하여 대량 작업으로 배열을 만들어 각 대량 쓰기 문서를 배열에 푸시합니다. 쓰기 명령은 1000 개가 넘는 연산을 받아 들일 수 있기 때문에 루프를 1000 번 반복 할 때 작업을 그룹화하여 최대 1000 번의 작업을 수행하고 어레이를 다시 초기화해야합니다.
var cursor = db.test.find({
"salary": { "$exists": true, "$type": 2 },
"dob": { "$exists": true, "$type": 2 }
}),
bulkUpdateOps = [];
cursor.snapshot().forEach(function(doc){
var newSalary = parseInt(doc.salary),
newDob = new ISODate(doc.dob);
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "salary": newSalary, "dob": newDob } }
}
});
if (bulkUpdateOps.length === 1000) {
db.test.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.test.bulkWrite(bulkUpdateOps); }