Mongodb - 数据模型更改,将数组转换为字符串的最佳方式

Mongodb - Data model change, optimal way of converting array to string

我们之前的数据模型假设某个字段,暂且暂且称它为field,可以包含多个值,所以我们将其建模为一个数组。

初始模型:

{
  field: ['val1]
}

然后我们意识到(1000 万个文档之后)情况并非如此,并更改为:

{
  field: 'val1;
}

我认为迁移到新模型很简单,但显然并非如此。

我试过了:

db.collection.update({},{$rename: {"field.0": 'newField'}})

但它抱怨说数组元素不能用在 $rename 运算符的第一位。 据我了解,在更新操作中您不能将一个字段值分配给另一个字段值,我调查了聚合框架,但我想不出办法。

我也试过 foreach,但是速度太慢了:

db.coll.find({"field":{$exists:true}}).snapshot().forEach(function(doc) 
{
  doc.newField = doc.field[0];
  delete doc.field;
  db.coll.save(doc);
});

我使用 bash 脚本将它并行化,我能够达到大约 200 updates/s,这意味着 10.000.000/(200*60*60)= 14h,等待相当长的时间,而不考虑超时错误我处理 bash 脚本,但那会浪费更多时间。

所以现在我问,批量操作或聚合框架是否有可能加快这个过程?

会选择批量操作,因为它们允许执行批量更新操作,这些操作只是服务器顶部的抽象,可以轻松构建批量操作,从而简化您的更新。当 bulk API 批量发送写入操作时,您可以获得大型集合的性能提升,甚至更好的是,它会为您提供有关成功和失败的真实反馈。在批量更新中,您将以 1000 次为单位向服务器发送操作,这会给您带来更好的性能,因为您不会向服务器发送每个请求,每 1000 个请求只发送一次:

var bulk = db.collection.initializeOrderedBulkOp(),   
    counter = 0;

db.collection.find({"field": { "$exists": true, "$type": 4 }}).forEach(function(doc) { 
    var updatedVal = doc.field[0];
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "field": updatedVal }
    });

    counter++;
    if (counter % 1000 == 0) {
        bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
        bulk = db.collection.initializeUnorderedBulkOp();
    }
});

// Clean up queues
if (counter % 1000 != 0) { bulk.execute(); }