如何最有效地更新MongoDB中的大量文档
How to update a large number of documents in MongoDB most effeciently?
我想最有效地更新大量(>10000)文档。
我的第一个天真的方法是在JS级别上进行,编写脚本首先获取_id,然后循环遍历_id并通过_id调用更新(fulldocs或$set补丁)。
我遇到了内存问题,还将数据分割成最多500个块文档(打开和关闭连接)似乎工作不好。
那么我该如何在MongoDB级别上解决这个问题呢
最佳实践?
我有3个常见的用例,通常是维护工作流:
1.更改属性值的类型,而不更改值
// before
{
timestamp : '1446987395'
}
// after
{
timestamp : 1446987395
}
2.根据现有属性的值添加新属性
// before
{
firstname : 'John',
lastname : 'Doe'
}
// after
{
firstname : 'John',
lastname : 'Doe',
name : 'John Doe'
}
3.只需添加或删除文档中的属性
// before
{
street : 'Whatever Ave',
street_no : '1025'
}
// after
{
street : 'Whatever Ave',
no : '1025'
}
谢谢你帮忙。
如果您的MongoDB服务器是2.6或更高版本,最好使用允许执行批量update
操作的写命令Bulk API,这些操作只是服务器上的抽象,以便轻松构建批量操作。这些批量操作主要有两种类型:
- 订单批量操作。这些操作按顺序执行所有操作,并在第一次写入错误时出错
- 无序批量操作。这些操作并行执行所有操作,并汇总所有错误。无序的批量操作不能保证执行顺序
注意,对于2.6以上的旧服务器,API将对操作进行下变频。然而,不可能100%下变频,因此可能存在一些边缘情况,即它无法正确报告正确的数字。
对于您的三个常见用例,您可以实现这样的Bulk API:
情况1.更改属性值的类型,而不更改值:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
// Handle error
if(err) throw err;
// Get the collection and bulk api artefacts
var col = db.collection('users'),
bulk = col.initializeOrderedBulkOp(), // Initialize the Ordered Batch
counter = 0;
// Case 1. Change type of value of property, without changing the value.
col.find({"timestamp": {"$exists": true, "$type": 2} }).each(function (err, doc) {
var newTimestamp = parseInt(doc.timestamp);
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "timestamp": newTimestamp }
});
counter++;
if (counter % 1000 == 0 ) {
bulk.execute(function(err, result) {
// re-initialise batch operation
bulk = col.initializeOrderedBulkOp();
});
}
});
if (counter % 1000 != 0 ){
bulk.execute(function(err, result) {
// do something with result
db.close();
});
}
});
案例2.根据现有属性的值添加新属性:
MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
// Handle error
if(err) throw err;
// Get the collection and bulk api artefacts
var col = db.collection('users'),
bulk = col.initializeOrderedBulkOp(), // Initialize the Ordered Batch
counter = 0;
// Case 2. Add new property based on value of existing property.
col.find({"name": {"$exists": false } }).each(function (err, doc) {
var fullName = doc.firstname + " " doc.lastname;
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "name": fullName }
});
counter++;
if (counter % 1000 == 0 ) {
bulk.execute(function(err, result) {
// re-initialise batch operation
bulk = col.initializeOrderedBulkOp();
});
}
});
if (counter % 1000 != 0 ){
bulk.execute(function(err, result) {
// do something with result
db.close();
});
}
});
案例3.只需添加或删除文档中的属性。
MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
// Handle error
if(err) throw err;
// Get the collection and bulk api artefacts
var col = db.collection('users'),
bulk = col.initializeOrderedBulkOp(), // Initialize the Ordered Batch
counter = 0;
// Case 3. Simply adding removing properties from documents.
col.find({"street_no": {"$exists": true } }).each(function (err, doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "no": doc.street_no },
"$unset": { "street_no": "" }
});
counter++;
if (counter % 1000 == 0 ) {
bulk.execute(function(err, result) {
// re-initialise batch operation
bulk = col.initializeOrderedBulkOp();
});
}
});
if (counter % 1000 != 0 ){
bulk.execute(function(err, result) {
// do something with result
db.close();
});
}
});
相关文章:
- MongoDB (php) - 以数组而不是多个属性的形式返回文档属性
- 如何从多个不同的html页面获得mongodb文档的用户输入
- 如何在mongodb(mongose)中覆盖子文档的数组属性
- 如何获取文档数组中元素的计数-MongoDB
- 如何在MongoDB中检索子文档引用
- 如何在mongoDB中过滤子文档
- MongoDB/Mongoose-使用geoNear的聚合;子文档
- 将多级 mongodb 文档转换为 Backbone.js 模型/集合
- 收集订阅者的流星事件,用于在 mongodb 中新插入文档
- MongoDB 删除重复的子文档
- MongoDB findAndModify:>>>查找和更新文档数组中的对象
- 是否可以引用猫鼬(MongoDB)上的子文档
- 更新数组中的嵌入文档 - Mongodb + Node Driver
- 向文档 mongodb 添加新字段
- 如果文档不存在,如何创建文档MongoDB Javascript
- 导入BSON文档MongoDB时出错
- 更新数组从文档(MongoDB)在Javascript不工作
- Mapreduce与内部文档mongodb排序
- 省略子文档MongoDB中的某些结果
- 查询子文档MongoDB Node.JS