我使用mongodb + node.js + mongoose.js ORM后端。
假设我有一些没有_id字段的对象嵌套数组
mongoose.Schema({
nested: [{
_id: false, prop: 'string'
}]
})
然后我想将_id字段广告到所有嵌套的对象,因此mongoose架构将是
mongoose.Schema({
nested: [{
prop: 'string'
}]
})
然后我应该运行一些脚本来修改生产数据库,对吗?处理此类变更的最佳方法是什么?哪种工具(或方法)最适合用于实施变更?
答案 0 :(得分:12)
无架构数据库的一个显着优势是您不必使用新架构布局更新整个数据库。如果数据库中的某些文档没有特定信息,那么您的代码可以执行相应的操作,或者选择现在对该记录执行任何操作。
另一种选择是懒洋洋地更新文件 - 只有在再次查看文件时才会这样做。在这种情况下,您可能会选择具有每个记录/文档版本标记 - 最初可能不会出现(因此表示'版本0')。即使这是可选的。相反,您的数据库访问代码会查找它需要的数据,如果它不存在,因为它是在代码更新后添加的新信息,那么它将尽可能地填充结果。
对于您的示例,将_id:false
转换为标准MongoId
字段,在读取代码(或在更新后写回)并且当前设置_id:false
时,则进行更改并仅在绝对需要时才写入。
答案 1 :(得分:10)
您确实必须编写将遍历集合的脚本并为每个文档添加新字段。但是,如何执行此操作取决于数据库的大小和存储系统的性能。向文档添加字段将改变其大小,从而在大多数情况下导致重定位。此操作对IO有影响,并受其限制。如果你的集合只有几千个文档,可能高达十万个,那么你可以在一个循环中迭代它,因为整个集合可能适合内存,所有IO都会在之后发生。但是,如果集合跨越可用内存,则该方法更复杂。我们通常遵循MongoDB的生产使用的后续步骤:
文件大小和睡眠时间必须通过实验确定。通常,您希望在迁移期间避免使用mongostats中的QR / QW。对于较慢驱动器上的较大集合(如亚马逊上的EBS),这种IO安全方法可能需要数小时到数天。
答案 2 :(得分:0)
在扩展@Michael Korbakov答案的同时,我用mongo
shell脚本(请参阅MongoDB Reference Manual关于mongo
shell脚本)实现了他的步骤。
重要提示:如MongoDB Reference Manual中所述,在mongo
shell上运行脚本可以提高性能,因为它可以减少每次批量获取和批量执行时的连接延迟。
应该考虑的一个缺点是mongo
shell命令始终是同步的,但是批量执行已经为我们解决了并行性(对于每个块),因此对于这种用例我们非常有用。
代码:
// constants
var sourceDbName = 'sourceDb';
var sourceCollectionName = 'sourceColl';
var destDbName = 'destdb';
var destCollectionName = 'destColl';
var bulkWriteChunckSize = 1000;
// for fetching, I figured 1000 for current bulkWrite, and +1000 ready for next bulkWrite
var batchSize = 2000;
var sourceDb = db.getSiblingDB(sourceDbName);
var destDb = db.getSiblingDB(destDbName);
var start = new Date();
var cursor = sourceDb[sourceCollectionName].find({}).noCursorTimeout().batchSize(batchSize);
var currChunkSize = 0;
var bulk = destDb[destCollectionName].initializeUnorderedBulkOp();
cursor.forEach(function(doc) {
currChunkSize++;
bulk.insert({
...doc,
newProperty: 'hello!',
}); // can be changed for your need, if you want update instead
if (currChunkSize === bulkWriteChunckSize) {
bulk.execute();
// each bulk.execute took for me 130ms, so i figured to wait the same time as well
sleep(130);
currChunkSize = 0;
bulk = destDb[destCollectionName].initializeUnorderedBulkOp();
}
});
if (currChunkSize > 0) {
bulk.execute();
currChunkSize = 0;
}
var end = new Date();
print(end - start);
cursor.close();