在我的网络抓取项目中,我需要将前一天抓取的数据从移动mongo_collection
到mongo_his_collection
我正在使用此查询来移动数据
for record in collection.find():
his_collection.insert(record)
collection.remove()
它工作正常,但有时当 MongoDBcollection
包含超过10k 行时它会中断
建议我一些优化的查询,这将占用更少的资源并完成相同的任务
在我的网络抓取项目中,我需要将前一天抓取的数据从移动mongo_collection
到mongo_his_collection
我正在使用此查询来移动数据
for record in collection.find():
his_collection.insert(record)
collection.remove()
它工作正常,但有时当 MongoDBcollection
包含超过10k 行时它会中断
建议我一些优化的查询,这将占用更少的资源并完成相同的任务
您可以为此使用MapReduce作业。
MapReduce 允许您指定一个输出集合来存储结果。
当你有一个 map 函数以它自己的 _id 作为键发出每个文档和一个 reduce 函数返回值数组的第一个(在这种情况下只是因为 _id 是唯一的)条目时,MapReduce 本质上是一个复制操作source-collection 到 out-collection。
未经测试的代码:
db.runCommand(
{
mapReduce: "mongo_collection",
map: function(document) {
emit(document._id, document);
},
reduce: function(key, values) {
return values[0];
},
out: {
merge:"mongo_his_collection"
}
}
)
查询中断是因为您没有限制 find()。当您在服务器上创建游标时,mongod 将尝试将整个结果集加载到内存中。如果您的集合太大,这将导致问题和/或失败。
为避免这种情况,请使用跳过/限制循环。这是Java中的示例:
long count = 0
while (true) {
MongoClient client = new MongoClient();
DBCursor = client.getDB("your_DB_name").getCollection("mongo_collection").find().sort(new BasicDBObject("$natural", 1)).skip(count).limit(100);
while (cursor.hasNext()) {
client.getDB("your_DB_name").getCollection("mongo_his_collection").insert(cursor.next());
count++;
}
}
这会起作用,但您也可以通过批处理写入来获得更好的性能。为此,从游标构建一个 DBObject 数组,并通过一次插入一次将它们全部写入。
此外,如果在您复制时更改了集合,则无法保证您将遍历所有文档,因为如果它们的大小增加,有些文档可能最终会被移动。
如果您的两个集合都在同一个数据库中,我相信您正在寻找renameCollection。
如果没有,很遗憾您必须手动执行此操作,使用有针对性的 mongodump / mongorestore 命令:
mongodump -d your_database -c mongo_collection
mongorestore -d your_database -c mongo_his_collection dump/your_database/mongo_collection.bson
请注意,我只是从头顶输入了这两个命令,而没有实际测试它们,因此请确保在生产中运行它们之前检查它们。
[编辑]:对不起,我刚刚意识到这是你需要定期做的事情。在这种情况下,mongodump / mongorestore
可能不是最好的解决方案。我认为您的解决方案没有任何问题-如果您编辑问题以解释“它中断”的含义,这将有所帮助。
您可以尝试mongodump和mongorestore。
你可以renameCollection
直接用它来做。或者,如果在不同的 mongods 上,请使用cloneCollection
.
参考: