【问题标题】:How to copy a collection from one database to another in MongoDB如何在 MongoDB 中将集合从一个数据库复制到另一个数据库
【发布时间】:2012-07-18 06:41:34
【问题描述】:

有没有简单的方法来做到这一点?

【问题讨论】:

  • 公认的答案可以说是 2012 年最好的方法,但现在 db.cloneCollection() 通常是更好的解决方案。这里有几个最近的答案涉及到这个,所以如果你从谷歌来这里(就像我一样)看看所有的答案!
  • 请务必阅读其他答案,以确保它符合您的需求,而不仅仅是 @kelvin 在他/她的情况下
  • @Naman 复制收集的用例是什么,我的意思是你需要任何命令或者手动处理可以吗?对于手动过程,只需安装studio3T 连接两个数据库并右键单击要复制的集合,单击选项“复制集合”,然后转到第二个数据库,右键单击“集合”目录并单击选项“粘贴集合” "。
  • @turivishal 这绝对是一种方式,但命令行工具更加可靠,并且可以立即支持随升级发布的功能。顺便说一句,我已经提高了赏金来奖励现有的答案。 :)

标签: mongodb mongo-collection


【解决方案1】:

最好的方法是先mongodump 然后mongorestore。您可以通过以下方式选择收藏:

mongodump -d some_database -c some_collection

[可选地,将转储文件 (zip some_database.zip some_database/* -r) 和 scp 压缩到别处]

然后恢复它:

mongorestore -d some_other_db -c some_or_other_collection dump/some_collection.bson

some_or_other_collection 中的现有数据将被保留。这样您就可以将集合从一个数据库“附加”到另一个数据库。

在 2.4.3 版之前,您还需要在复制数据后重新添加索引。从 2.4.3 开始,此过程是自动的,您可以使用 --noIndexRestore 禁用它。

【讨论】:

  • 如果你有密码保护的 mongo 实例,mongodump 似乎不起作用(你应该!)
  • 它适用于受 PW 保护的数据库,您只需在参数中传递身份验证
  • 这比 find/forEach/insert 快得多,在我的例子中是 2 分钟 vs 2 小时
  • 使用--username 而非--password 传入数据库的用户名以获得密码提示。最好不要将密码放在命令行中(最终将其保存到 .bash_history 或类似文件中)
  • 次要:我在由 some_database 命名的子文件夹中找到了该文件,所以这对我有用:mongorestore -d some_other_db -c some_or_other_collection dump/some_database/some_collection.bson
【解决方案2】:

目前 MongoDB 中没有可以执行此操作的命令。请注意JIRA ticket with related feature request

你可以这样做:

db.<collection_name>.find().forEach(function(d){ db.getSiblingDB('<new_database>')['<collection_name>'].insert(d); });

请注意,这样,两个数据库需要共享同一个 mongod 才能工作。

除此之外,您可以对一个数据库中的集合进行 mongodump,然后将集合 mongorestore 到另一个数据库。

【讨论】:

  • 请注意,如果您copy in the JS shell BSON 文档在此过程中被解码为 JSON,因此某些文档可能会导致类型更改。 mongodump/mongorestore 通常是更好的方法。
  • 同意。这更像是一个玩弄外壳的有趣建议。另外,它不会带来索引。如果我这样做,我会每次都执行 mongodump/mongorestore。
  • 谢谢。请注意,您的代码中有错字,没有关闭 getSiblingDB 函数。这是更正后的代码: db..find().forEach(function(d){ db.getSiblingDB('')[''].insert(d); });跨度>
  • 这对于在测试运行之间从黄金副本重置测试 mongodb 非常有效。您可以使用 db.getCollection(name).find().forEach 对要复制的所有集合名称执行 for 循环,而不是对集合名称进行硬编码,并提供一个具有 db.getSiblingDB("otherdb") 的函数。 getCollection(name).insert(d).
  • 这对于大型收藏集是否有效?
【解决方案3】:

实际上,有一个命令可以将集合从一个数据库移动到另一个数据库。只是不叫“移动”或“复制”。

要复制一个集合,您可以在同一个数据库上克隆它,然后移动克隆的集合。

要克隆:

> use db1
switched to db db1

> db.source_collection.find().forEach(
      function(x){
          db.collection_copy.insert(x)
      }
  );

移动:

> use admin
switched to db admin

> db.runCommand(
      {
          renameCollection: 'db1.source_collection',
          to              : 'db2.target_collection'
      }
  );

其他答案更适合复制集合,但如果您要移动它,这尤其有用。

【讨论】:

  • Thx 效果很好!只需在'db1.source_collection' 中添加一个撇号即可
  • 而不是“使用管理员”后跟“db.runCommand(...”你可以只做一个命令,“db.adminCommand(...”
  • 这不适用于您无法重命名的共享集合。
  • 逐个文档复制集合需要很长时间!
【解决方案4】:

我会滥用 mongo cli mongo doc 中的连接功能。这意味着您可以启动一个或多个连接。 如果您想将客户集合从 test 复制到同一服务器中的 test2。首先你启动 mongo shell

use test
var db2 = connect('localhost:27017/test2')

正常查找并将前 20 条记录复制到 test2。

db.customer.find().limit(20).forEach(function(p) { db2.customer.insert(p); });

或按某些标准过滤

db.customer.find({"active": 1}).forEach(function(p) { db2.customer.insert(p); });

只需将 localhost 更改为 IP 或主机名即可连接到远程服务器。我使用它来将测试数据复制到测试数据库进行测试。

【讨论】:

  • 正如我评论 Jason 的建议,请注意,如果您在 JS shell 中复制,BSON 文档在此过程中会被解码为 JSON,因此某些文档可能会导致类型更改。与Limitations of eval 有类似的考虑,这将是在数据库之间(尤其是在同一台服务器上)复制大量数据的较慢过程。所以 mongodump/mongorestore FTW :)。
【解决方案5】:

如果在两个远程 mongod 实例之间,使用

{ cloneCollection: "<collection>", from: "<hostname>", query: { <query> }, copyIndexes: <true|false> } 

http://docs.mongodb.org/manual/reference/command/cloneCollection/

【讨论】:

  • copyIndexes 选项字段实际上不受尊重。索引总是被复制的。请参阅 SERVER-11418
  • 包装在 db.runCommand() 即 db.runCommand({ cloneCollection: "", from: "", query: { } })
  • 如何将其用于从一个远程 mongo 到另一个远程 mongo 的增量更新?
  • 我整天都将用户数据添加到一个 mongo 实例中。在一天结束时,我需要将新添加的行转移到另一个 mongo 实例。如何做到这一点?
  • @NishantKumar 尝试在查询中设置: { } 此代码: $where: function() { today = new Date(); // today.setHours(0,0,0,0);返回 (this._id.getTimestamp() >= today) 。见stackoverflow.com/questions/42456375/…
【解决方案6】:

我通常会这样做:

use sourcedatabase;
var docs=db.sourcetable.find();
use targetdatabase;
docs.forEach(function(doc) { db.targettable.insert(doc); });

【讨论】:

    【解决方案7】:

    对于大型收藏,您可以使用Bulk.insert()

    var bulk = db.getSiblingDB(dbName)[targetCollectionName].initializeUnorderedBulkOp();
    db.getCollection(sourceCollectionName).find().forEach(function (d) {
        bulk.insert(d);
    });
    bulk.execute();
    

    这将节省大量时间。 就我而言,我正在复制包含 1219 个文档的集合:iter vs Bulk(67 秒 vs 3 秒)

    【讨论】:

    • 这样更好,更高效,减少数据库,适用于任何大小的数据集。
    • 如果您对超过 300k 条记录执行此操作,您可能需要在 find 之后和 foreach 之前添加一个 .limit(300000)。否则系统可能会锁定。为了安全起见,我通常将批量更改限制在 100k 左右。根据计数和限制将整个事物包装在一个 for 循环中。
    • 我们应该插入(一个)还是更喜欢批量插入很多?
    【解决方案8】:

    您可以使用聚合框架来解决您的问题

    db.oldCollection.aggregate([{$out : "newCollection"}])
    

    需要注意的是,oldCollection 中的索引不会复制到 newCollection 中。

    【讨论】:

    • 还应注意,任何现有的newCollection 在插入新数据之前都会被删除。
    【解决方案9】:

    我知道这个问题已经得到解答,但是我个人不会回答@JasonMcCays,因为游标流式传输,如果仍在使用该集合,这可能会导致无限游标循环。相反,我会使用快照():

    http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database

    @bens answer 也是一个不错的答案,不仅适用于集合的热备份,而且 mongorestore 不需要共享同一个 mongod。

    【讨论】:

      【解决方案10】:

      这可能只是一个特例,但是对于具有两个随机字符串字段(长度为 15-20 个字符)的 100k 文档的集合,使用哑 mapreduce 的速度几乎是 find-insert/copyTo 的两倍:

      db.coll.mapReduce(function() { emit(this._id, this); }, function(k,vs) { return vs[0]; }, { out : "coll2" })
      

      【讨论】:

        【解决方案11】:

        使用 pymongo,你需要在同一个 mongod 上拥有两个数据库,我做了以下操作:


        db = 原始数据库
        db2 = 要复制到的数据库

        cursor = db["<collection to copy from>"].find()
        for data in cursor:
            db2["<new collection>"].insert(data)
        

        【讨论】:

        • 如果数据量很大,这将花费很多时间。或者,您可以使用bulk_insert
        • 是的,这只是我发现为我工作的一种快速而肮脏的方式,我的数据库不是太大,但也不小,也不会花费太长时间,但是是的,你是对的.
        • 你好@vbhakta,不幸的是光标为我返回空数组。我做了什么:cursor = db['my-node-js'].collectioName.find()。你可以理解 my-node-js 是数据库名称。我执行 print(cursor.toArray()) 时得到的是 '[ ]' 和 print(cursor.count()) 打印 0。
        【解决方案12】:

        收集副本有多种方法。请注意,复制可以发生在同一个数据库、不同数据库、分片数据库或mongod 实例中。一些工具对于大型馆藏复制非常有效。

        使用 $merge 进行聚合: 将聚合管道的结果写入指定的集合。请注意,复制可以跨数据库发生,甚至是分片集合。创建一个新集合或替换现有集合。 4.2 版中的新功能。 示例:db.test.aggregate([ { $merge: { db: "newdb", coll: "newcoll" }} ])

        与 $out 的聚合: 将聚合管道的结果写入指定的集合。请注意,复制只能发生在同一个数据库中。创建一个新集合或替换现有集合。 示例:db.test.aggregate([ { $out: "newcoll" } ])

        mongoexport 和 mongoimport: 这些是命令行工具。 mongoexport 生成集合数据的 JSON 或 CSV 导出。使用mongoimport 将导出的输出用作目标集合的源。

        mongodump 和 mongorestore: 这些是命令行工具。 mongodump 实用程序用于创建数据库或集合内容的二进制导出。 mongorestore 程序将数据从mongodump 创建的二进制数据库转储加载到目标。

        db.cloneCollection(): 将集合从远程 mongod 实例复制到当前 mongod 实例。 自 4.2 版起已弃用。

        db.collection.copyTo(): 将集合中的所有文档复制到新的集合中(在同一数据库中)。 自 3.0 版起已弃用。从 4.2 版本开始,MongoDB 这条命令无效。

        注意:除非说上述命令是从mongo shell 运行的。

        参考:The MongoDB Manual

        您还可以使用喜欢的编程语言(例如 Java)或环境(例如 NodeJS),使用适当的驱动程序软件编写程序来执行复制 - 这可能涉及使用查找和插入操作或其他方法。这个查找插入也可以从mongo shell 执行。

        您还可以使用 MongoDB Compass 等 GUI 程序进行收集复制。

        【讨论】:

          【解决方案13】:

          正如其他答案中给出的那样,最快的解决方案应该是mongodump / mongorestore。无需将转储保存到本地磁盘,您可以将转储直接通过管道传输到 mongorestore:

          mongodump --db=some_database --collection=some_collection --archive=- | mongorestore --nsFrom="some_database.some_collection" --nsTo="some_or_other_database.some_or_other_collection" --archive=-
          

          如果您运行共享集群,则默认情况下不会对新集合进行分片。所有数据最初都写入您的主分片。这可能会导致磁盘空间出现问题,并为balancing 增加集群负载。在导入数据之前最好像这样pre-split你的集合:

          sh.shardCollection("some_or_other_database.some_or_other_collection", { <shard_key>: 1 });
          db.getSiblingDB("config").getCollection("chunks").aggregate([
             { $match: { ns: "some_database.some_collection"} },
             { $sort: { min: 1 } },
             { $skip: 1 }
          ], { allowDiskUse: true }).forEach(function (chunk) {
             sh.splitAt("some_or_other_database.some_or_other_collection", chunk.min)
          })
          

          【讨论】:

            【解决方案14】:

            如果 RAM 不是问题,使用 insertManyforEach 循环快得多。

            var db1 = connect('<ip_1>:<port_1>/<db_name_1>')
            var db2 = connect('<ip_2>:<port_2>/<db_name_2>')
            
            var _list = db1.getCollection('collection_to_copy_from').find({})
            db2.collection_to_copy_to.insertMany(_list.toArray())
            

            【讨论】:

              【解决方案15】:

              这不会解决您的问题,但是 mongodb shell 有一个 copyTo 方法,可以将集合复制到同一数据库中的另一个

              db.mycoll.copyTo('my_other_collection');
              

              它还可以从 BSON 转换为 JSON,因此正如其他人所说,mongodump/mongorestore 是最好的选择。

              【讨论】:

              • 优秀。可悲的是,Mongo shell reference 似乎没有提到这种方法。
              • 是的,我知道,但是 MongoDB shell 很棒,如果您输入 db.collname.[TAB],您将看到集合对象上的所有可用方法。此技巧适用于所有其他对象。
              • 问题是这些命令缺乏帮助!能够看到代码是很有用的,尽管在方法调用中省略括号。
              • 遗憾的是,该命令自 3.0 版以来已被弃用。
              【解决方案16】:

              如果一些heroku用户在这里绊倒并且像我一样想将一些数据从临时数据库复制到生产数据库,反之亦然,这就是你如何非常方便地做到这一点(注意我希望那里没有拼写错误,无法检查它atm.,我会尽快确认代码的有效性):

              to_app="The name of the app you want to migrate data to"
              from_app="The name of the app you want to migrate data from"
              collection="the collection you want to copy"
              mongohq_url=`heroku config:get --app "$to_app" MONGOHQ_URL`
              parts=(`echo $mongohq_url | sed "s_mongodb://heroku:__" | sed "s_[@/]_ _g"`)
              to_token=${parts[0]}; to_url=${parts[1]}; to_db=${parts[2]}
              mongohq_url=`heroku config:get --app "$from_app" MONGOHQ_URL`
              parts=(`echo $mongohq_url | sed "s_mongodb://heroku:__" | sed "s_[@/]_ _g"`)
              from_token=${parts[0]}; from_url=${parts[1]}; from_db=${parts[2]}
              mongodump -h "$from_url" -u heroku -d "$from_db" -p"$from_token" -c "$collection" -o col_dump
              mongorestore -h "$prod_url" -u heroku -d "$to_app" -p"$to_token" --dir col_dump/"$col_dump"/$collection".bson -c "$collection"
              

              【讨论】:

                【解决方案17】:

                您始终可以使用 Robomongo。从 v0.8.3 开始,有一个工具可以通过右键单击集合并选择“将集合复制到数据库”来执行此操作

                详情见http://blog.robomongo.org/whats-new-in-robomongo-0-8-3/

                这个功能是removed in 0.8.5,因为它有漏洞,所以如果你想尝试的话,你必须使用 0.8.3 或 0.8.4。

                【讨论】:

                • Robomongo 的这个功能还不稳定。让它发挥作用的机会是 50/50。
                • 这似乎已从 0.8.5 中删除
                【解决方案18】:

                使用“Studio3T for MongoDB” 通过单击数据库、集合或特定集合具有导出和导入工具 下载地址:https://studio3t.com/download/

                【讨论】:

                  【解决方案19】:

                  这里有很多正确的答案。我会选择 mongodumpmongorestore 以管道方式进行大型收藏:

                  mongodump --db fromDB --gzip --archive | mongorestore --drop --gzip --archive --nsFrom "fromDB.collectionName" --nsTo "toDB.collectionName"
                  

                  虽然如果我想快速复制,虽然速度很慢,但很有效:

                  use fromDB 
                  db.collectionName.find().forEach(function(x){
                     db.getSiblingDB('toDB')['collectionName'].insert(x);
                  });"
                  

                  【讨论】:

                  • 我试过mongorestore --uri mongodb+srv://iser:pass@test.sub1.mongodb.net --nsFrom "weblog.contractors" --nsTo "weblog.contractors_temp",但它只是试图覆盖整个博客数据库。在mongorestore之前我做过:mongodump --uri mongo+srv://asd:asda@asd.asd.com/weblog。请小心。
                  【解决方案20】:

                  就我而言,我必须在新集合中使用旧集合中的属性子集。所以我最终在对新集合调用 insert 时选择了这些属性。

                  db.<sourceColl>.find().forEach(function(doc) { 
                      db.<newColl>.insert({
                          "new_field1":doc.field1,
                          "new_field2":doc.field2,
                          ....
                      })
                  });`
                  

                  【讨论】:

                    【解决方案21】:

                    在 MongoDB 中将集合 (myCollection1) 从一个数据库复制到另一个数据库,

                    **Server1:**
                    myHost1.com 
                    myDbUser1
                    myDbPasword1
                    myDb1
                    myCollection1
                    
                    outputfile:
                    myfile.json 
                    
                    **Server2:**
                    myHost2.com 
                    myDbUser2
                    myDbPasword2
                    myDb2
                    myCollection2 
                    

                    你可以这样做:

                    mongoexport  --host myHost1.com --db myDb1 -u myDbUser1  -p myDbPasword1 --collection myCollection1   --out  myfile.json 
                    

                    然后:

                    mongoimport  --host myHost2.com --db myDb2 -u myDbUser2  -p myDbPasword2 --collection myCollection2   --file myfile.json 
                    

                    另一种情况,使用 CSV 文件:

                    Server1:
                    myHost1.com 
                    myDbUser1
                    myDbPasword1
                    myDb1
                    myCollection1
                    fields.txt
                        fieldName1
                        fieldName2
                    
                    outputfile:
                    myfile.csv
                    
                    Server2:
                    myHost2.com 
                    myDbUser2
                    myDbPasword2
                    myDb2
                    myCollection2
                    

                    你可以这样做:

                    mongoexport  --host myHost1.com --db myDb1 -u myDbUser1  -p myDbPasword1 --collection myCollection1   --out  myfile.csv --type=csv
                    

                    在 csv 文件中添加 clolumn 类型 (name1.decimal(),name1.string()..) 然后:

                    mongoimport  --host myHost2.com --db myDb2 -u myDbUser2  -p myDbPasword2 --collection myCollection2   --file myfile.csv --type csv --headerline --columnsHaveTypes
                    

                    【讨论】:

                      【解决方案22】:

                      这可以使用 Mongo 的 db.copyDatabase 方法来完成:

                      db.copyDatabase(fromdb, todb, fromhost, username, password)
                      

                      参考:http://docs.mongodb.org/manual/reference/method/db.copyDatabase/

                      【讨论】:

                      • OP 想要复制一个集合——而不是整个数据库。
                      猜你喜欢
                      • 2020-07-17
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-10-30
                      • 1970-01-01
                      • 2017-04-06
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多