在同一数据库中将Mongo集合复制到另一个集合

38

我有一个名为test的mongo db,其中包含两个集合collection1collection1_backup。 如何用collection1_backup中的数据替换collection1的内容。

9个回答

69

考虑到集合名称以_backup结尾,最好的方法可能是使用mongorestore:http://docs.mongodb.org/manual/reference/mongorestore/

不过,在这种情况下,具体情况而定。如果集合未被分片,您可以使用renameCollectionhttp://docs.mongodb.org/manual/reference/command/renameCollection/),或者使用更多手动的方法(在JavaScript代码中):

db.collection1.drop(); // Drop entire other collection
db.collection1_backup.find().forEach(function(doc){
   db.collection1.insert(doc); // start to replace
});

这些是最常用的方法。


3
与汇总相反的最慢方法。 - Denis Denisov
@DenisDenisov 你有任何证据吗?我想象这两种方法(手动方法和聚合框架)肯定不会比专门设计用于复制表的复制函数更快,尽管它可能会考虑到安全措施。它们将复制相对相同的内容,需要将所有行读入活动工作集,然后将它们保存回来,我真的看不出聚合框架为什么会更快,更不用说它并不是为这样的事情而设计的了。 - Sammaye
是的,我刚刚在一个大集合上进行了检查。 集合和索引使用 wiredTiger.configString='block_compressor=zstd'。 聚合几乎立即由 percona-server-mongodb-server-4.2.6-6.el7.x86_64 执行。 - Denis Denisov
@DenisDenisov 立即完成?即使在处理200万条记录的集合时,另一个用户也需要约3分钟的时间来记录 https://stackoverflow.com/a/37870870/383478 ,而立即完成比磁盘实际写入更快,这违反了科学定律。 - Sammaye
1
无论如何,db.collection1_backup.aggregate([ { $match: {} }, { $out: "collection1" } ]) 的速度比 find().forEach(..insert=~100rec/s` 更快。参考链接:https://forums.meteor.com/t/iterating-over-mongo-cursor-too-slow-server-side/19531/13 https://mongobooster.useresponse.com/topic/slow-performance-using-foreach https://dev59.com/EI3da4cB1Zd3GeqPvBu8 - Denis Denisov
显示剩余2条评论

23
这可以通过使用这个简单的命令来完成。
db.collection1_backup.aggregate([ { $match: {} }, { $out: "collection1" } ])

这个命令将删除所有collection1的文档,然后在collection1中创建collection1_backup的克隆。
通用命令如下:
db.<SOURCE_COLLECTION>.aggregate([ { $match: {} }, { $out: "<TARGET_COLLECTION>" } ])

如果 TARGET_COLLECTION 不存在,上述命令将会创建它。

这个答案实际上应该被接受为正确答案。 - undefined

6

另外还有一个非常实用的功能: 将集合导出为JSON文件

mongoexport --collection collection1_backup --out collection1.json

从JSON文件导入集合

mongoimport --db test --collection collection1 --file collection1.json

要从备份/转储文件中导入单个集合,需要将*.bson文件转换为*.json文件,方法是使用

bsondump collection1_backup.bson > collection1_backup.json

10
一般来说,复制集合时最好使用mongodumpmongorestore,因为将文档转换为JSON然后再转回来可能会影响数据类型的保真度。在BSON中存在一些数据类型,在JSON中可能有不同的表示方式,其中没有严格的JSON等效项。使用mongoimport/mongoexport取决于您的数据,但这是一个重要的注意事项。 - Stennie
@Stennie 还要注意的是,执行 mongodump / mongorestore 操作可以保留索引。因此,如果您想在集合之间复制文档,则无法使用该方法进行还原。如果您想在集合之间复制文档,应该使用 mongoexport 和 mongoimport。 - ivandov
1
@ivandov 你可以使用 mongorestore --noIndexRestore 跳过重新创建索引(除了必需的 _id 索引)。请注意,mongorestore(截至 MongoDB 3.4)仅执行插入操作;如果具有相同 _id 的文档已存在,则不会更新或替换它。mongoimport 工具支持 upserts(在 3.4 中支持合并),但仅适用于文本格式,而不是 MongoDB 的原生 BSON 格式。如果您想在 MongoDB 部署之间完全重建数据(以及可选的集合元数据),则仍然建议使用 mongodumpmongorestore - Stennie

2
"最初的回答" 只需要这样做。
//删除 collection1
db.collection1.drop();

//将collection1_backup中的数据复制到collection1中

db.collection1.insert(db.collection1_backup.find({},{_id:0}).toArray());

1
您可以使用简单的命令备份MongoDB集合。它只适用于MongoDB 4.0或更早版本。
db.sourceCollectionName.copyTo('targetCollectionName')

您的 targetCollectionName 必须使用单引号或双引号

注意:

db.collection.copyTo() 方法在内部使用 eval 命令。因此,db.collection.copyTo() 操作会获取全局锁,阻塞所有其他读写操作,直到 db.collection.copyTo() 完成。


copyTo 可能需要一些特殊权限,并且在从 BSON 转换为 JSON 时可能会改变数据。 - Dan Dascalescu
1
copyTo已被弃用:https://docs.mongodb.com/manual/reference/method/db.collection.copyTo/。引用: “从版本4.2开始,MongoDB删除了eval命令。已弃用的db.collection.copyTo()命令,它包装了eval命令,只能在MongoDB 4.0或更早版本上运行。有关行为和示例,请参阅手册的4.0或更早版本。” - Porcupine

1
使用Java驱动程序
尝试以下内容:
public void copyTo(String db,String sourceCollection,String destinationCollection,int limit) throws        
UnknownHostException {

    MongoClient mongo = new MongoClient("localhost", 27017);
    DB database = mongo.getDB(db);
    DBCollection collection = database.getCollection(sourceCollection);
    DBCursor dbCursor = collection.find().limit(limit);
    List<DBObject> list =  dbCursor.toArray();
    DBCollection destination =  database.getCollection(destinationCollection);
    destination.insert(list, WriteConcern.NORMAL); //WRITE CONCERN is based on your requirment.

}

使用 import com.mongodb.client.MongoCollection;,我添加了以下代码段:MongoCollection database = template.getCollection("database"); List documents = new ArrayList<>(); database.find().iterator().forEachRemaining(documents::add); MongoCollection destination = template.getCollection("destination"); destination.insertMany(documents); database.drop(); - Kyofa

1
更好的方法是使用 .toArray()
 db.collection1.drop(); // Drop entire other collection

 // creates an array which can be accessed from "data"
 db.collection1_backup.find().toArray(function(err, data) {

      // creates a collection and inserting the array at once
      db.collection1.insert(data);
 });

2
关于大小优化怎么样?如果我的集合是2GB,我需要有2GB的内存吗? - Amantel

0

删除集合1

然后使用以下查询

var cursor = db.collection1_backup.find();
var data = [];
while(cursor.hasNest()){
    data.push(cursor.next());
}

db.collection1.insertMany(data)

0

只需运行这个简单的查询...

db.collection1.insertMany(db.collection1_backup.find({}).toArray())

运行这个简单的查询,将所有数据从 collection1_backup 集合复制到 collection1 集合。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接