Aakash Kag
Aakash Kag

Reputation: 362

Find key contain dot and replace with @

I have nested object which can have any number of key at any depth. I want to replace "." in all keys(if contain) with "@" How we can do this in efficient way.

Example Node js object

obj:{
        "BotBuilder.Data.SessionState": {
            "lastAccess": 1492886892545,
            "version": 14,
            "callstack": [
                {
                    "id": "*:/",
                    "state": {
                        "BotBuilder.Data.WaterfallStep": 0,
                        "BotBuilder.Data.Intent": "welcomeDialog"
                    }
                }
            ]
        }

Currently i am using hard coded solution , but any keys can be possible in object at any level which contain "." I want generalize way to solve this problem

My code :

replaceDot:function(doc){
    var finalobj={}
    var finaldata={}
    var finalcallstack=new Array();
    console.log("doc==>",doc)
    var callstack=doc["data"]["BotBuilder.Data.SessionState"]["callstack"]
    for(var i = 0; i < callstack.length; i++) {
        var tempcallstack={}
        if("BotBuilder.Data.WaterfallStep" in callstack[i]["state"]){
            tempcallstack["id"]=callstack[i]["id"]
            var tempstate={}
            tempstate["state"]=callstack[i]["state"]
            tempstate["state"]["BotBuilder@Data@WaterfallStep"]=tempstate["state"]["BotBuilder.Data.WaterfallStep"]
            tempstate["state"]["BotBuilder@Data@Intent"]=tempstate["state"]["BotBuilder.Data.Intent"]
            delete tempstate["state"]["BotBuilder.Data.WaterfallStep"]
            delete tempstate["state"]["BotBuilder.Data.Intent"]
            tempcallstack["state"]=tempstate["state"];
            finalcallstack.push(tempcallstack);
        }
        else{
            finalcallstack.push(callstack[i]);
        }
    }   
    var obj={}
    finalobj["lastAccess"]=doc["data"]["BotBuilder.Data.SessionState"]["lastAccess"]
    finalobj["version"]=doc["data"]["BotBuilder.Data.SessionState"]["version"]
    finalobj["callstack"]=finalcallstack;
    obj["BotBuilder@Data@SessionState"]=finalobj
    var secondrootobj={"BotBuilder@Data@SessionState":finalobj}
    return secondrootobj;
}

Upvotes: 1

Views: 163

Answers (1)

Gershom Maes
Gershom Maes

Reputation: 8140

Here's a function that takes an object or array, and target and replacement values for the keys of that object. It will then return a new object where instances of target are replaced with replacement (using String.prototype.replace) in the resulting object's keys.

var substituteKeyDeep = function(obj, target, replacement) {
    // Get the type of the object. Array for arrays, Object for objects, null for anything else.
    try {
        var type = obj.constructor === Array ? Array
          : (obj.constructor === Object ? Object : null);
    } catch (err) {
        // A try/catch is actually necessary here. This is because trying to access the `constructor` property
        // of some values throws an error. For example `null.constructor` throws a TypeError.
        var type = null;
    }
    
    if (type === Array) {
        // Simply do a recursive call on all values in array
        var ret = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            ret[i] = substituteKeyDeep(obj[i], target, replacement);
        }
    } else if (type === Object) {
        // Do a recursive call on all values in object, AND substitute key values using `String.prototype.replace`
        var ret = {};
        for (var k in obj) {
            ret[k.replace(target, replacement)] = substituteKeyDeep(obj[k], target, replacement);
        }
    } else {
        // For values that aren't objects or arrays, simply return the value
        var ret = obj;
    }
    
    return ret;
};

var data = {
    "BotBuilder.Data.SessionState": {
        "lastAccess": 1492886892545,
        "version": 14,
        "callstack": [
            {
                "id": "*:/",
                "state": {
                    "BotBuilder.Data.WaterfallStep": 0,
                    "BotBuilder.Data.Intent": "welcomeDialog"
                }
            }
        ]
    }
};

var dataWithRenamedKeys = substituteKeyDeep(data, /\./g, '@');

console.log(dataWithRenamedKeys);

Note that in the example, the replacement value (/\./g) is a regex expression, not a string. This is because a regex expression with the global modifier (g) is required to replace ALL instances of the occurrence, not just the first, in the object's keys.

EDIT: Quick disclaimer! This solution will exceed the stack if substituteKeyDeep is called with an object that has circular references.

Upvotes: 1

Related Questions