3

有没有办法将所有项目集合复制到新集合而不循环所有项目?我找到了一种通过 DBCursor 循环的方法:

...
DB db = mongoTemplate.getDb();
DBCursor cursor = db.getCollection("xxx").find();

//loop all items in collection
while (cursor.hasNext()) {
   BasicDBObject b = (BasicDBObject) cursor.next();
   // copy to new collection 
   service.createNewCollection(b);
}
...

你能建议在java中复制而不循环所有项目吗?
(不在 mongo shell 中,使用 java 实现)Tnx。

4

5 回答 5

6

在 MongoDB 2.6 中,添加了$out 聚合运算符,它将聚合结果写入集合。这提供了一种简单的方法,可以使用 Java 驱动程序(我使用 Java 驱动程序版本 2.12.0)将集合中的所有项在服务器端复制到同一数据库中的另一个集合:

// set up pipeline
List<DBObject> ops = new ArrayList<DBObject>();
ops.add(new BasicDBObject("$out", "target")); // writes to collection "target"

// run it
MongoClient client = new MongoClient("host");
DBCollection source = client.getDB("db").getCollection("source")
source.aggregate(ops);

单行版本:

source.aggregate(Arrays.asList((DBObject)new BasicDBObject("$out", "target")));

根据文档,对于大型数据集(>100MB),您可能需要使用 allowDiskUse 选项(聚合内存限制),尽管我在 >2GB 集合上运行它时没有遇到该限制,因此它可能不适用到这个特定的管道,至少在 2.6.0 中。

于 2014-05-02T16:24:33.790 回答
2

我遵循了插入对象数组的建议:将 MongoDB 集合移动到另一个集合的更好方法 这将我的时间从 45 分钟减少到 2 分钟。这是Java代码。

        final int OBJECT_BUFFER_SIZE = 2000;
        int rowNumber = 0;
        List<DBObject> objects;
        final int totalRows = cursor.size();
        logger.debug("Mongo query result size: " + totalRows);
            // Loop design based on this:
            // https://stackoverflow.com/questions/18525348/better-way-to-move-mongodb-collection-to-another-collection/20889762#20889762
            // Use multiple threads to improve
            do {
                logger.debug(String.format("Mongo buffer starts row %d - %d copy into %s", rowNumber,
                        (rowNumber + OBJECT_BUFFER_SIZE) - 1, dB2.getStringValue()));
                cursor = db.getCollection(collectionName.getStringValue()).find(qo)
                        .sort(new BasicDBObject("$natural", 1)).skip(rowNumber).limit(OBJECT_BUFFER_SIZE);
                objects = cursor.toArray();
                try {
                    if (objects.size() > 0) {
                        db2.getCollection(collectionName.getStringValue()).insert(objects);
                    }
                } catch (final BSONException e) {
                    logger.warn(String.format(
                            "Mongodb copy %s %s: mongodb error. A row between %d - %d will be skipped.",
                            dB1.getStringValue(), collectionName.getStringValue(), rowNumber, rowNumber
                                    + OBJECT_BUFFER_SIZE));
                    logger.error(e);
                }
                rowNumber = rowNumber + objects.size();
            } while (rowNumber < totalRows);

缓冲区大小似乎很重要。10,000 的大小可以正常工作;但是,出于各种其他原因,我选择了较小的尺寸。

于 2014-04-05T01:41:37.470 回答
0

我的想法是从 Java 驱动程序发送cloneCollection管理命令。下面是一个部分示例。

DB db = mongo.getDB("admin");
DBObject cmd = new BasicDBObject();
cmd.put("cloneCollection", "users.profiles");//the collection to clone

//add the code here to build the rest of the required fields as JSON string 

CommandResult result = db.command(cmd);

我记得利用驱动程序的JSON.parse(...) util API 让驱动程序在幕后构建结构。试试这个,因为这更简单。

注意:我还没有尝试过,但我相信这会奏效。

于 2013-04-25T02:59:08.603 回答
0

你可以使用谷歌番石榴来做到这一点。要从迭代器中获取 Set,您可以使用Sets#NewHashSet(Iterator)

于 2013-04-23T09:10:12.627 回答
0

如果目标集合在同一个数据库中,我认为使用 kellogg.lee 声明的聚合运算符是最好的方法。

为了复制到在不同 mongod 实例上运行的其他数据库中的集合,可以使用以下方法:

第一种方法:

List<Document> documentList = sourceCollection.find().into(new ArrayList<Document>);
targetCollection.insertMany(documentList);

但是,如果源集合很大,此方法可能会导致 outOfMemory 错误。

第二种方法:

sourceCollection.find().batchSize(1000).forEach((Block<? super Document>) document -> targetCollection.insertOne(document));

这种方法比第一种方法更安全,因为它不保留整个文档的本地列表,并且可以根据内存要求确定块大小。但是,这可能比第一个慢。

于 2020-04-02T14:24:53.203 回答