user3142695
user3142695

Reputation: 17322

Change structure of mongodb collection in meteor

I have to change the document structure of a collection. Based on this post (MongoDB/Meteor: Add unique ID to every array element) I'm using the code:

Collection.find({}).forEach(function (doc) {
    addId(doc.group);
});

function addId(obj) {
    if (Object.prototype.toString.call(obj).indexOf('Array') >= 0) {
        obj.forEach(function(item) {
            item.id = item.id || Random.id();
            addId(item);
        });
    }
    else if (typeof obj == 'object') {
        Object.keys(obj).forEach(function(key) {
            addId(obj[key]);
        });
    }
}

My problem now is to get the Collection updated correctly. The addId() function is working well. If I do a console.log on item.id I get the ids. But How do I do the collection update? Maybe it is a stupid question, but I'm really stuck on that thing...

Collection.update({ _id: doc._id }, { ???? } );

Background info

I want to add an id to every group element and to every data element:

{
    "_id" : "wLXDvjDvbsxzfxabR",
    "group" : [
        {
            "title" : "title 1",
            "data" : [
                {
                    "note" : "text"
                }
            ]
        },
        {
            "title" : "title 2",
            "data" : [
                {
                    "note 1" : "text"
                },
                {
                    "note 2" : "text"
                },
                {
                    "note 3" : "text"
                }
            ]
        }
    ]
}

result should be (for every document in the collection)

{
    "_id" : "wLXDvjDvbsxzfxabR",
    "group" : [
        {
            "id" : "dfDFSfdsFDSfdsFws",
            "title" : "title 1",
            "data" : [
                {
                    "id" : "efBDEWVvfdvsvsdvs",
                    "note" : "text"
                }
            ]
        },
        {
            "id" : "fdsfsFDSFdsfFdsFd",
            "title" : "title 2",
            "data" : [
                {
                    "id" : "WVvfsvVFSDWVDSVsv",
                    "note 1" : "text"
                },
                {
                    "id" : "qqdWSdksFVfSVSSCD",
                    "note 2" : "text"
                },
                {
                    "id" : "MZgsdgtscdvdsRsds",
                    "note 3" : "text"
                }
            ]
        }
    ]
}

Upvotes: 2

Views: 67

Answers (1)

chridam
chridam

Reputation: 103305

You can achieve this by way of using the Bulk API operations to do the updates. These allow for the execution of bulk update operations which are simply abstractions on top of the server to make it easy to build bulk operations, thus streamlining your updates. These bulk operations come mainly in two flavours:

  • Ordered bulk operations. These operations execute all the operation in order and error out on the first write error.
  • Unordered bulk operations. These operations execute all the operations in parallel and aggregates up all the errors. Unordered bulk operations do not guarantee order of execution.

You can get raw access to the collection and database objects in the npm MongoDB driver through rawCollection and rawDatabase methods on Mongo.Collection:

var bulkOp = Collection.rawCollection().initializeUnorderedBulkOp(),
    counter = 0;

Collection.find({}).forEach(function(doc) {
    var changedObj = addId(doc);    
    bulkOp.find({"_id": doc._id}).updateOne({ "$set": changedObj });

    counter++;
    if (counter % 1000 == 0) {
        // Execute per 1000 operations and re-initialize every 1000 update statements
        bulkOp.execute(function(e, r) {
            console.info('r.nMatched', r.nMatched, 'r.nModified', r.nModified);
        });
        bulkOp = Collection.rawCollection().initializeUnorderedBulkOp();
    }
}); 

// Clean up queues
if (counter % 1000 != 0){
    bulkOp.execute(function(e, r) {
        console.info('r.nMatched', r.nMatched, 'r.nModified', r.nModified);
    });
}


function addId(obj) {
    if (Object.prototype.toString.call(obj).indexOf('Array') >= 0) {
        obj.forEach(function(item) {
            item.id = item.id || Random.id();
            addId(item);
        });
    }
    else if (typeof obj == 'object') {
        Object.keys(obj).forEach(function(key) {
            addId(obj[key]);
        });
    }   
    return obj;
}

Upvotes: 1

Related Questions