0

I want to copy the contents from one collection to another.

in mongod this can be done:

db.tempMongoItem.find().forEach( function(x){db.mongoItem.insert(x)} )

Using Java Mongo Driver, I try:

DB db = mongoClient.getDB("mydb")

CommandResult result = db.command("db.tempMongoItem.find().forEach( function(x){db.mongoItem.insert(x)} )")

But I get:

result = [serverUsed:localhost:27017, ok:0.0, errmsg:no such cmd: db.tempMongoItem.find().forEach( function(x){db.mongoItem.insert(x)} ), code:59, bad cmd:[db.tempMongoItem.find().forEach( function(x){db.mongoItem.insert(x)} ):true]]

Any ideas?

More Than Five
  • 9,959
  • 21
  • 77
  • 127

3 Answers3

4

You need to emulate the same thing JS is doing in Java, which means getting a cursor and iterating over it, inserting each document into new collection.

Something like this (coll is current, coll2 is new collection):

DBCursor cursor = coll.find();
try {
   while(cursor.hasNext()) {
       coll2.insert(cursor.next());
   }
} finally {
   cursor.close();
}

Both coll and coll2 are assumed to be DBCollection type.

Since it appears you are copying within the same DB, there is another way to do this if you are using 2.6 MongoDB using aggregation framework $out stage:

db.collection.aggregate({"$out":"newCollection"});

Note that this is limited to outputting into the same DB that original collection is in.

Asya Kamsky
  • 41,784
  • 5
  • 109
  • 133
  • Thanks. In my case, this is a huge dataset. Your approach would bring in a massive amount of data into memory - yeah? If so, is there anyway to avoid that. – More Than Five Jul 09 '14 at 21:53
  • that's exactly what the JS code does. If you want to keep it on the server and you're using 2.6 you can use aggregation framework. But it can only copy within the same DB - do you want to create new collection in a different DB or same DB? Your code looks like it's the same so there is another way! I'll edit the answer. – Asya Kamsky Jul 09 '14 at 21:59
  • @AsyaKamsky could you please add the java code equivalent of `db.collection.aggregate({"$out":"newCollection"});` ? thanks. edit: found something in [this](http://stackoverflow.com/questions/16164413/mongodb-copy-collection-in-java-without-looping-all-items) question – Joey Baruch Feb 15 '17 at 10:46
  • The other answer to this question shows Java code to aggregate with "$out" – Asya Kamsky Feb 15 '17 at 19:02
0

The following JAVA code will copy the collection from source to destination for a given database name (using mongodb-driver 3.0.4)

/** Clone a collection.
*
* @param fromCollectionName - The name of collection to be cloned
* @param toCollectionName   - The name of the cloned collection
* @param dbName             - The name of the database
*/
public void cloneCollection(String fromCollectionName, String toCollectionName, String dbName) throws MongoException {
    MongoCollection toCol = this.getCollection(toCollectionName, dbName);
    if (toCol != null) {
      throw new MongoException("The destination collection already exists.");
    }
    List<Document> ops = new ArrayList<>();
    ops.add(new Document("$out",toCollectionName));
    MongoCollection sourceCollection = this.getCollection(fromCollectionName, dbName);
    sourceCollection.aggregate(ops);
}

public MongoCollection getCollection(String collection, String dbName) {
    MongoClient mongo = new MongoClient(new ServerAddress("localhost", Integer.parseInt(port)));
    MongoDatabase database = mongo.getDatabase(dbName);
    return curdb.getCollection(collection); 
}

Please note that this will not copy over the indices that you have created in source collection. You will have to copy the indices seperately

DPancs
  • 588
  • 6
  • 14
0

Following up on Asya's response, you can use Java 8 Lambda functions to do:

collSource.find().forEach((Block<Document>) collTarget::insertOne);
Nic Cottrell
  • 9,401
  • 7
  • 53
  • 76