HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Is this a good algorithm to unflat js objects?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thisunflatobjectsalgorithmgood

Problem

I am dealing with a scenario where I get data in the following form:

var data = {
    'user.name': 'renatoargh',
    'user.age': 27,
    'user.interests.0.description': 'coding',
    'user.interests.0.receiveNotifications': true,
    'user.interests.1.description': 'bungee jumping',
    'user.interests.1.receiveNotifications': false
};


So in order to validate and persist this data I decided to create a way to unflat these strings into regular JS objects, and send them to MongoDb (since it is schema-less).

I coded an algorithm that I am unsure that works for most cases so I created a fiddle that seems to be able to deal with an extreme case, full of nested arrays.

Can someone point any week point or case in which my algorithm would fail? Any kind of advice will be appreciated.

Link to the fiddle here!

Heres the code, where messageObject is the array and the output is in messageTree

function forEachOwnProperty(object, iterator) {
    for(var property in object){
        if(object.hasOwnProperty(property)) {
            iterator(property, object[property]);
        }
    }
}

forEachOwnProperty(messageObject, function(property, messages) {
    property = property.split('.');

    var currentNode = messageTree;

    for(var i = 0; i < property.length; i++) {
        var currentProperty = property[i];

        if(typeof currentNode[currentProperty] === 'undefined') {
            if(i === property.length - 1) {
                currentNode[currentProperty] = messages
            } else {
                if(/^\+?(0|[1-9]\d*)$/.test(property[i + 1])) {
                    currentNode[currentProperty] = [];    
                } else {
                    currentNode[currentProperty] = {};    
                }            
            }
        }

        currentNode = currentNode[currentProperty];
    }
});

Solution

Nice code!

-
You should point out assumptions in a comment. You could document, for instance, that if the first encountered subproperty of a property is numeric, it's treated as an array.

-
I would rename messages to something like value. property is fine, but you could also consider key.

-
Right now, your code won't work with direct arrays. The following messageObject won't produce the expected result:

messageObject = {
    'array.0': 'Code',
    'array.1': 'Review'
};


-
There are some very specific edge cases: messageObject = { 'constructor.name': 'renatoargh' } will return an empty object. I'm not really sure what can be done about this though...

-
Finally, just for fun, you can use something like var key = property.splice(-1); to eliminate the second if in your for loop. Of course, after the loop, you'd have to add currentNode[key] = messages;.

Code Snippets

messageObject = {
    'array.0': 'Code',
    'array.1': 'Review'
};

Context

StackExchange Code Review Q#59162, answer score: 3

Revisions (0)

No revisions yet.