5

Is there anyway to duplicate an collection through the nodejs mongodb driver?

i.e. collection.copyTo("duplicate_collection");

3 Answers 3

3

You can eval copyTo() server-side though it will block the entire mongod process and won't create indexes on the new collection.

var copyTo = "function() { db['source'].copyTo('target') };"

db.eval(copyTo, [], function(err, result) {
  console.log(err);
});

Also note the field type warning.

"When using db.collection.copyTo() check field types to ensure that the operation does not remove type information from documents during the translation from BSON to JSON. Consider using cloneCollection() to maintain type fidelity."

Sign up to request clarification or add additional context in comments.

Comments

2

Try to avoid .eval() if this is something you want to do regularly on a production system. It's fast, but there are problems.

A better approach would be to use The "Bulk" operations API, and with a little help from the "async" library:

db.collection("target",function(err,target) {

    var batch = target.initializeOrderedBulkOp();
    counter = 0;

    var cursor = db.collection("source").find();
    var current = null;       

    async.whilst(
        function() {
            cursor.nextObject(function(err,doc) {
                if (err) throw err;

                // .nextObject() returns null when the cursor is depleted
                if ( doc != null ) {
                    current = doc;
                    return true;
                } else {
                    return false;
                }
            })
        },
        function(callback) {
            batch.insert(current);
            counter++;

            if ( counter % 1000 == 0 ) {
                batch.execute(function(err,result) {    
                    if (err) throw err;
                    var batch = target.initializeOrderedBulkOp();
                    callback();
                });
            }
        },
        function(err) {
            if (err) throw err;
            if ( counter % 1000 != 0 ) 
                batch.execute(function(err,result) {
                    if (err) throw err;

                    // job done
                });
        }
    );    


});

It's fast, not as fast as .eval() but does not block either the application or server.

Batch operations will generally take as many operations as you throw at them, but using a modulo as a limiter allows a little more control and essentially avoids loading an unreasonable amount of documents in memory at a time. Keep in mind that whatever the the case the batch size that is sent cannot exceed more that 16MB between executions.

1 Comment

I like @Justin solution because it blocks the mongodb process. I should have mentioned it in the question beforehand however.
0

Another option to duplicate a collection would be to use aggregate method on a collection and the $out parameter. Here is an example inside of an async function:

const client = await MongoClient.connect("mongodb://alt_dev:aaaaa:27018/meteor");
const db = client.db('meteor');
const planPrice = await db.collection('plan_price');
const planPriceCopy = await planPrice.aggregate([{$match: {}}, {$out: planPriceUpdateCollection}]);
await planPriceCopy.toArray();

This will create a copy of the original collection with all of its content.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.