67

I need to convert a js object to another object for passing onto a server post where the names of the keys differ for example

var a = {
    name : "Foo",
    amount: 55,
    reported : false,
    ...
    <snip/>
    ...
    date : "10/01/2001"
    } 

needs to turn into

a = {
  id : "Foo",
  total : 55,
  updated: false,
  ...
  <snip/>
  ... 
  issued : "10/01/2001"
  }

where I have lookup obj available for mapping all the keys

var serverKeyMap = {
    name : "id",
    amount : "total",
    reported : "updated",
     ...
    date : "issue"
    }

Is there a function available in underscore.js or jQuery that I can use that does this functionality?

thanks

1
  • 8
    Not underscore, but lodash has _.mapKeys for modifying keys of an object. Commented Oct 25, 2015 at 14:54

16 Answers 16

77

I know you didn't mention lodash and the answers already solve the problem, but someone else might take advantage of an alternative.

As @CookieMonster mentioned in the comments, you can do this with _.mapKeys:

_.mapKeys(a, function(value, key) {
    return serverKeyMap[key];
});

And the fiddle: http://jsfiddle.net/cwkwtgr3/

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

2 Comments

The side effects are strong with this one.
@DFlores009 like what? That would be more helpful.
42

Similar to @pimvdb, you can also do it with a _.reduce:

_.reduce(a, function(result, value, key) {
    key = map[key] || key;
    result[key] = value;
    return result;
}, {});

Fiddle: http://jsfiddle.net/T9Lnr/39/

3 Comments

seems to still work for me @wegginho, it prints to the console
I'm getting an error that underscore is not defined
underscore is attached as an external resource, perhaps where it's hosted is blocked for you? try opening the file to see if you have access to it
38

As far as I know there is no function built into either of these two libraries. You can make your own fairly easily, though: http://jsfiddle.net/T9Lnr/1/.

var b = {};

_.each(a, function(value, key) {
    key = map[key] || key;
    b[key] = value;
});

Comments

11

You could copy the values to the new properties with standard JavaScript, and remove the original properties with omit, as follows:

a.id = a.name;
a.total = a.amount;
a.updated = a.reported;
a = _.omit(a, 'name', 'amount', 'reported');

2 Comments

Please add some explanation. Currently, your answer is flagged "low quality" and might get removed.
By using this method you can not change all keys with have more than one value.
3
// key_map: {old_name1: new_name1, ... }
function rename_keys(object, key_map, is_picked=false){
  keys = _.keys(key_map);
  new_keys = _.values(key_map);
  picked = _.pick(object, keys);
  renamed = _.object(new_keys, _.values(picked));
  if(is_picked) return renamed;

  return _.chain(object).omit(keys).extend(renamed).value();
}

This may be slower than above answers.

Comments

2

No there is no function in either library that explicitly renames keys. Your method is also the fastest (see jsperf tests.) Your best bet, if possible, is to refactor either the client side or server side code so the objects are the same.

1 Comment

The test cases in the benchmark doesn't even look equal.
2

I have a transformation operator and would just like to apply it to all keys. I forked pimvdb's fiddle to produce a simple example. In this case it Capitalizes the key. And it dynamically builds the keymap, which I needed to assure works (thanks JSFiddle).

Here is the changed code:

var keymap = {};
_.each(a, function(value, key) {
    var oldkey = key;
    key = capitalize(key);
    keymap[oldkey] = key;
});
_.each(a, function(value, key) {
    key = keymap[key] || key;
    b[key] = value;
});

Fiddle: http://jsfiddle.net/mr23/VdNjf/

2 Comments

Although the example is contrived, in real life I used this to build a 'cleanup' keymap using the first record of a dataset, and then apply it to the rest (which may include additional 'loads' of data).
i ended up using the _.replace() solution above, but i started by looking at your solution and plunkr. works well. thanks
2

It's been solved here https://stackoverflow.com/a/30940370/1360897

var keyMapping = {'PropertyA': 'propertyA', ..., 'PropertyF': 'propertyNEW'}

and also a mapping of old and new values, like this

var valueMapping = {'Y': true, 'F': false}

And then using _.map and _.transform, you can transform the object, like this

var result = _.map(allItems, function(currentObject) {
    return _.transform(currentObject, function(result, value, key) {
        if (key === 'PropertyF' || key === 'PropertyG') {
            value = valueMapping(value);
        }
        result[keyMapping[key]] = value;
    });
});

Comments

2

Why don't you use this simple java script ? Value of any key:value pair should be string/number/Boolean.

<script type="text/javascript">    
    var serverKeyMap = {
        name : "id",
        amount : "total",
        reported : "updated"
    };

    var a = {
        name : "Foo",
        amount: 55,
        reported : false
    };

    var b={}; // b is object where you will get your output

    for(i in serverKeyMap) b[serverKeyMap[i]]=a[i];

    console.log(b); // It gives what you need.

</script>

Comments

1

As user2387823 was saying above 👆 using omit is a great option. For example you could write something like this

function updateObjKey(obj, currentKey, newKey) {
    var keyValue = obj[currentKey];
    obj = _.omit(obj, [currentKey]);
    obj[newKey] = keyValue;
    return obj;
  }

Comments

1

this ES2015/2017 version 🧙‍♂️

function objectMap(source,keyMap) {
    return Object.entries(keyMap).reduce((o,[key , newKey]) => {
            o[newKey]=source[key]
            return o;},{})
}

const obj = {
    name : "Foo",
    amount: 55,
    reported : false,
    date : "10/01/2001"
    }
    
const  serverKeyMap = {
    name : "id",
    amount : "total",
    reported : "updated",
    date : "issue"
    }
    
const result = objectMap(obj,serverKeyMap);

console.log('🎬 =>' , result);

[Object.entries][1] is es2017 feture will return object key and value as array

[["name", "id"],["amount", "total"],...]

Comments

1

You really don't need underscore/lodash for this ... nowadays anyways (I realize the question was asked 9 years ago, but this question is (still) ranked highly in search results and I came across it today :-) )

Here's another plain ES2015/2017 version that I like, inspired by @malbarmavi's answer (there's probably a bunch of other plain JS functions out there, but I didn't come across any others in my brief search):

// A general key transform method. Pass it a function that accepts the old key and returns
// the new key.
//
// @example
//   obj = transformKeys(obj, (key) => (
//    key.replace(/\b(big)\b/g, 'little')
//  ))
export function transformKeys(source, f) {
  return Object.entries(source).reduce((o, [key, value]) => {
    o[f(key) || key] = value
    return o
  }, {})
}
 
// Provide an object that maps from old key to new key
export function rekeyObject(source, keyMap) {
  transformKeys(source, key => keyMap[key])
}

Comments

1

I referred the lodash documentation ans found mapKeys https://lodash.com/docs/4.17.15#mapKeys

_.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
  return key + value;
});
// => { 'a1': 1, 'b2': 2 }

this perfectly renames the keys and return an object containing the modified desirable object

Comments

0

Using underscore omit and spread operator.

a = _.omit({
  ...a,
  id: a.name,
  total: a.amount,
  updated: a.reported,
}, ['name', 'amount', 'reported']);

Key assignments below spread operator loads new keys and omit omits the old ones.

Comments

0

You can create your new custom function :

lodash.rename = function(obj, keys, newKeys) {
  keys.map((key, index) => {
    if(lodash.includes(lodash.keys(obj), key)) {
      obj[newKeys[index]] = lodash.clone(obj[key], true);
      delete obj[key];
    }
  });
  return obj;
};

Or else if you want to edit only one keyName:

lodash.rename = function(obj, key, newKey) {
    if(lodash.includes(lodash.keys(obj), key)) {
      obj[newKeys[index]] = lodash.clone(obj[key], true);
      delete obj[key];
    }
  return obj;
};

Comments

0

Using lodash

var obj = _.renameKeys( { 1 : "Geeks",  
            2 : "Computer_Science_Portal" }, 
            { 1 : "g", 2 : "c" }); 

so in your case, you want to apply the serverKeyMap onto object a :

var obj = _.renameKeys(a, serverKeyMap);

from https://www.geeksforgeeks.org/lodash-_-renamekeys-method/

1 Comment

For clarity: this function is not built into Lodash proper, but a an extension added by the lodash-contrib package. Likewise, for Underscore there is a renameKeys in Underscore-contrib (which lodash-contrib might be a fork of): documentcloud.github.io/underscore-contrib/#renamekeys.

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.