Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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];
    }
});
share|improve this question

1 Answer 1

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;.

share|improve this answer
    
Thank you @Schism, I will have a look at your suggestions and create some unit tests so I can improve the code. Then I'll edit the answer! (: –  renatoargh 19 hours ago
    
I tested you third point but it worked as expected for me. The problem is that nulls are added if I have something like messageObject = { 'array.0': 'code', 'array.2': 'review' } but this is the default behavior for JavaScript, for example: var a = []; a[10] = null; console.log(JSON.stringify(a, null, 4));will print a 10 positions array, filled with nulls. It makes me wonder wether I should consider this as the expected behavior or not (splice the nulls). What is your opinion? –  renatoargh 58 mins ago
    
@renatoargh Oh, for some reason it didn't seem to work yesterday; perhaps I mistyped something. I think the behaviour as-is should be considered expected, though depending on the use-case / application, it may be better to splice them out. tl;dr it looks great as it is right now! –  Schism 16 mins ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.