Simple method to modify json keys casing to camelCase from snake_case - javascript

I have lots of json parsing and all the json I am receiving is having keys in snake case like user_name. And for parsing I need it in camel case like userName.
The sample json file would look like this:
[{
"user_id" : 1,
"user_name" : "Abcd"
},
{
"org_id" : 11,
"org_name" : "some_name"
}
...
]
Expected output:
[{
"userId" : 1,
"userName" : "Abcd"
},
{
"orgId" : 11,
"orgName" : "some_name"
}
...
]
The json I am receiving is not having any particular fixed notation and it can be anything. But all the keys will be in snake case. And I need to convert it to camelCase.
What I cannot do is, find and replace, because it also replace snake casing strings in values as well.
Is there any easy method, which can do the same?

You can use npm package called: camelcase-keys-deep
https://www.npmjs.com/package/camelcase-keys-deep

You can do the following:
var keys = [];//this will contain the json with desired output
for(var i = 0;i<myObj.length;i++)//myObj is the variable that contains your json
{
Object.keys(myObj[i]).forEach(function(key){
if(keys.indexOf(key) == -1)
{
var newValue = {};
var value = myObj[i][key];
key = key.replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); });
newValue[key] = value;
keys.push(newValue);
}
});
}
//console.log(keys);
Hope this helps :)

So AKSHAY JAIN's implementation is pretty solid but it will delete the properties that are not in snake case. I fixed the implementation.
var arr = [{
"user_id": 1,
"user_name": "Abcd"
},
{
"org_id": 11,
"org_name": "some_name"
},
{
"personId": 12,
"personName": "otherName"
}];
arr.forEach(a => {
Object.keys(a).forEach(k => {
newK = k.replace(/(\_\w)/g, (m) => m[1].toUpperCase());
if (newK != k) {
a[newK] = a[k];
delete a[k];
}
});
});
console.log(arr);

If u use lodash I would suggest my solution for this:
snake_case -> camelCase
function camelCaseDeep(anything) {
const thing = _.cloneDeep(anything);
if (
_.isEmpty(thing) ||
(!_.isObject(thing) && !_.isArray(thing))
) {
return thing;
}
if (_.isArray(thing)) {
const arr = thing;
return arr.map(el => camelCaseDeep(el))
}
// thing can be only not empty object here
const objWithMappedKeys = _.mapKeys(thing, (value, key) => _.camelCase(key));
const objWithMappedValues = _.mapValues(objWithMappedKeys, value => camelCaseDeep(value));
return objWithMappedValues;
}
camelCase -> snake_case
function snakeCaseDeep(anything) {
const thing = _.cloneDeep(anything);
if (
_.isEmpty(thing) ||
(!_.isObject(thing) && !_.isArray(thing))
) {
return thing;
}
if (_.isArray(thing)) {
const arr = thing;
return arr.map(el => snakeCaseDeep(el))
}
// thing can be only not empty object here
const objWithMappedKeys = _.mapKeys(thing, (value, key) => _.snakeCase(key));
const objWithMappedValues = _.mapValues(objWithMappedKeys, value => snakeCaseDeep(value));
return objWithMappedValues;
}

var arr = [{
"user_id": 1,
"user_name": "Abcd"
},
{
"org_id": 11,
"org_name": "some_name"
}
];
arr.forEach(a => {
Object.keys(a).forEach(k => {
newK = k.replace(/(\_\w)/g, (m) => m[1].toUpperCase());
a[newK] = a[k];
delete a[k];
});
});
console.log(arr);

Related

Angular js filter an array of objects based on values in another array of objects

I have to filter an array of objects based on some preferences.
The Array I need to filter looks like this:
[
{
"id": "1",
"type": "book",
"name": "test"
},
{
"id": "2",
"type": "book2",
"name": "test2"
}
]
The preferences look like this:
[
{
'type': ["book", "book3"]
}
]
The filter should return all objects that matches the value of the preferences. So the desired result should be:
[
{
"id": "1",
"type": "book",
"name": "test"
}
]
I have tried to use the following function from the example I found here:
const filtered = products.filter(a => this.preferences.some(b => {
b.type == a.type
}
));
However, I am not getting the response I am expected with this sample code.
2nd question:
Here is a new preference:
[
{
'type': ["book", "book3"]
}, {
'name': ["test"]
}
]
second object is optional, how do I filter using this new preference?
Try this
const filtered = products.filter(a => this.preferences.some(b => {
return b.type.indexOf(a.type) > -1
}
));
You try to check if array equals string so it will never return true
UPD for the 2nd question
If you need more flexible code you can write something like this for 1 or more preferences.
const filtered = products.filter(a => {
// total matches for all preferences
let matches = 0;
this.preferences.forEach(b => {
// local match for a preference
let prefMatches = 0;
// iterate all preference keys for calculating local preference match
const bKeys = Object.keys(b);
bKeys.forEach(key => {
if (b[key].indexOf(a[key]) > -1) {
prefMatches += 1;
}
});
if (prefMatches === bKeys.length) {
matches += 1;
}
});
// so all preferences must match or it returns false
return matches === this.preferences.length;
});
If you want at least 1 match you can rewrite it like:
const filtered = products.filter(a => {
this.preferences.forEach(b => {
// local match for a preference
let prefMatches = 0;
// iterate all preference keys for calculating local preference match
const bKeys = Object.keys(b);
bKeys.forEach(key => {
if (b[key].indexOf(a[key]) > -1) {
prefMatches += 1;
}
});
// so at least one preference must match
if (prefMatches === bKeys.length) {
return true;
}
});
return false;
});

How to add dynamic keys with nested level from the array in javascript

Hi I want to create new object on the basis of path array. It will be dynamic. I tried with reduce but it is not giving correct result.
const obj = {
"e": [{
"name": "moviename",
"path": ["a"]
},
{
"name": "hero",
"path": ["a", "b"]
},
{
"name": "desc",
"path": ["c"]
},
{
"name": "udf",
"path": []
}
]
}
// this is what i want this object to be created programatically. after parsing above obj.
const output = {
"a": {
"moviename": "",
"b": {
"hero": ""
}
},
"c" : {
"desc": ""
},
"udf": ""
}
const payload = {};
obj.e.forEach((item) => {
if (item.path.length === 0) {
payload = {
...payload,
[item.name]: ''
};
} else {
item.path.reduce((o, s, index) => {
if ((index + 1) === item.path.length) {
return o[s] = {
[item.name]: ''
};
}
return o[s] = {};
}, payload);
}
});
console.log(payload);
You can use simple for loops -- reduce would also work (see further down), but I think the overhead of a callback is not worth it:
function convert(arr) {
const output = {};
for (const {name, path} of arr) {
let node = output;
for (let prop of path) {
node = (node[prop] ??= {});
}
node[name] = "";
}
return output;
}
const obj = {"e": [{"name": "moviename","path": ["a"]},{"name": "hero","path": ["a", "b"]},{"name": "desc","path": ["c"]},{"name": "udf","path": []}]};
console.log(convert(obj.e));
With reduce:
Using reduce it would translate to this:
function convert(arr) {
return arr.reduce((output, {name, path}) => {
let node = output;
for (let prop of path) {
node = (node[prop] ??= {});
}
node[name] = "";
return output;
}, {});
}
const obj = {"e": [{"name": "moviename","path": ["a"]},{"name": "hero","path": ["a", "b"]},{"name": "desc","path": ["c"]},{"name": "udf","path": []}]};
console.log(convert(obj.e));
With double reduce:
If the inner loop is also done through reduce, then:
function convert(arr) {
return arr.reduce((output, {name, path}) => {
path.reduce((node, prop) => node[prop] ??= {}, output)[name] = "";
return output;
}, {});
}
const obj = {"e": [{"name": "moviename","path": ["a"]},{"name": "hero","path": ["a", "b"]},{"name": "desc","path": ["c"]},{"name": "udf","path": []}]};
console.log(convert(obj.e));
The logical nullish assignment operator
If your environment has no support for ??= then use one of the following alternatives:
node[prop] ||= {}
(node[prop] = node[prop] ?? {})
(node[prop] = node[prop] || {})
Some comments on your code
As this function builds the object from scratch, it is not really necessary to treat intermediate versions of the object as immutable -- as your code attempts to do at least in the case of path.length == 0: just keep extending the object through mutation.
return o[s] = {}; is destructive: if the property was already created from a previously processed path, then this will overwrite whatever was already assigned to o[s].

Javascript/Typescript: Best way to append value in object based on condition from other object

Updated object keys
let conditionedObject = {
"isNameRequired": true,
"isCityRequired": false,
"isPostRequired": true
};
let myTotalData = {
data: {
"givenName": 'myname',
"street":"mystreet",
"cityName": 'mycity',
"postcode": 'mypost'
}
};
let resultData = {};
Both condionedObject and myTotalData comes from different source.
I would like to know the best way to create a new object based on the condionedObject,
example my condionedObject says I need only name and post so my resultData should return {"givenName":"myname","postcode":"mypost"}
conditionedObject.isNameRequired is for myTotalData.data.givenName, conditionedObject.isPostRequired is for myTotalData.data.postcode,
conditionedObject.isCityRequired is for myTotalData.data.cityName, all this will say whether myTotalData key is required to be placed in the new object.
Thanks in advance for all the suggestions and helps
You can use Array.prototype.reduce():
In this case I recommend you to create a new object to store the relationship between properties:
let conditionedObject = {
"isNameRequired": true,
"isCityRequired": false,
"isPostRequired": true
};
let myTotalData = {
data: {
"givenName": 'myname',
"street":"mystreet",
"cityName": 'mycity',
"postcode": 'mypost'
}
};
const reference = {
"isNameRequired": "givenName",
"isCityRequired": "cityName",
"isPostRequired": "postcode"
}
let resultData = {};
resultData =Object.entries(conditionedObject).reduce((obj, [key, value]) => {
if(value && myTotalData.data[reference[key]]) {
const prop = reference[key];
obj[prop] = myTotalData.data[prop];
}
return obj;
}, {});
console.log(resultData);
Here is my solution:
You need to change the keys in the object conditionedObject and remove the is- prefix so that they are the same as the keys in myTotalData. This way the check is easier later.
Then it's pretty straight-forward.
let conditionedObject: {[key: string]: boolean} = {
"isName": true,
"isCity": false,
"isPost": true
};
type DataType = {[key: string]: string};
let myTotalData: DataType = {
"name": 'myname',
"city": 'mycity',
"post": 'mypost'
};
let resultData: DataType = {};
for(const key in conditionedObject) {
// Ensure that the key is really part of this object
if(!conditionedObject.hasOwnProperty(key)) {
continue;
}
if(!conditionedObject[key]) {
continue;
}
const dataKey = key.startsWith("is")
? key.charAt(2).toLowerCase() + key.substring(3)
: key;
if(myTotalData.hasOwnProperty(dataKey)) {
resultData[dataKey] = myTotalData[dataKey];
}
}
console.log(resultData);
Output:
{
name: "myname",
post: "mypost"
}
You can use something like that, if you can be sure that the conditionedObject keys are always equal your myTotalData keys, but capitalized and with "is" on the front:
let capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
let prependIs = str => "is" + str
let conditionedObject = {
"isName": true,
"isCity": false,
"isPost": true
};
let myTotalData = {
"name": 'myname',
"city": 'mycity',
"post": 'mypost'
};
let filterData = (data, conditionObj) => Object.fromEntries(Object.entries(data)
.filter(([key, _]) => conditionObj[prependIs(capitalize(key))]))
// More verbose alternative for browsers which doesn't support `Object.fromEntries()`
let filterDataAlt = (data, conditionObj) => {
let result = {}
let filteredEntries = Object.entries(data)
.filter(([key, _]) => conditionObj[prependIs(capitalize(key))])
for (let [key, value] of filteredEntries) {
result[key] = value
}
return result
}
console.log(filterData(myTotalData, conditionedObject))
console.log(filterDataAlt(myTotalData, conditionedObject))

Filter boolean from an json object in javascript

I would like to filter all boolean values from an json object in javascript. I managed to get it working on a simple json object but in my case I have got a nested one. Here is an example of the object. I dont know how to manage this structure.
{
"User1":
{
"age":15,
"country":"sw",
"glasses":true,
"car":true,
"zip":1223,
"name":"Frank"
},
"User2":
{
"age":23,
"country":"fr",
"glasses":false,
"car":true,
"zip":5577,
"name":"Mike"
}
}
And as a result I would like to receive something like this:
{
"User1":{
"glasses":true,
"car":true
},
"User2":{
"glasses":false,
"car":true
}
}
const result = {};
for(const [key, value] of Object.entries(input)) {
const {glasses, car} = value;
result[key] = {glasses, car};
}
Just iterate over the objects entries and make some destructuring on the inner objects. Or if you really want every boolean:
const result = {};
for(const [key, value] of Object.entries(input)) {
const out = result[key] = {};
for(const [innerKey, innerValue] of Object.entries(value)) {
if(typeof innerValue === "boolean")
out[innerKey] = innerValue;
}
}
For actual JSON string, the JSON.parse reviver parameter can be used to exclude or modify values:
var j = '{"User1":{"age":15,"country":"sw","glasses":true,"car":true,"zip":1223,"name":"Frank"},"User2":{"age":23,"country":"fr","glasses":false,"car":true,"zip":5577,"name":"Mike"}}';
var o = JSON.parse(j, (k, v) => typeof v == 'number' || typeof v == 'string' ? void 0 : v);
console.log(o);
If you don't know which keys will be booleans, you can do it like this.
Let's say you assign that object to a variable.
var myObject = {
"User1": {
"age":15,
"country":"sw",
"glasses":true,
"car":true,
"zip":1223,
"name":"Frank"
},
"User2": {
"age":23,
"country":"fr",
"glasses":false,
"car":true,
"zip":5577,
"name":"Mike"
}
}
Then you can loop through the object and assign the filtered results to myBooleans.
var myBooleans = {};
Object.keys(myObject).forEach(function(key) {
var myNewUserObject = {};
Object.keys(myObject[key]).forEach(function(userKey) {
if (typeof myObject[key][userKey] === 'boolean') {
myNewUserObject[userKey] = myObject[key][userKey];
}
});
myBooleans[key] = myNewUserObject;
});
There is probably a pretty way to do with with n levels of object using recursion. But this will work for the shape of the data you provided.
Try this
function parse(obj , targetObject) {
var k;
if (obj instanceof Object) {
for (k in obj){
if(typeof(obj[k]) === "boolean"){
targetObject[k] = obj[k];
}
if(obj[k] instanceof Object) {
targetObject[k] = {};
parse(obj[k],targetObject[k]);
}
}
}
};
Call like this:
var target = {};
parse(myObj , target);
Hope this helps
This is how you can filter all the boolean values from object -
let input = {
"User1": {
"age": 15,
"country": "sw",
"glasses": true,
"car": true,
"zip": 1223,
"name": "Frank"
},
"User2": {
"age": 23,
"country": "fr",
"glasses": false,
"car": true,
"zip": 5577,
"name": "Mike"
}
};
let output = {};
Object.entries(input).map(([key, value], index) => {
output[key] = {};
Object.entries(value).
filter(([k, v], i) => typeof v === "boolean").
map(([k, v], i) => {
output[key][k] = v;
})
});
console.log(output);

How to convert snake case to camelcase in my app

I have a very weird issue in my lodash codes
I have something like
data = {
'id':'123',
'employee_name': 'John',
'employee_type': 'new'
}
var newObj = _.mapValues(data, function (value, key) {
var t = _.camelCase(key);
console.log(t) -> shows employeeName and employeeType
return _.camelCase(key);
});
I was expecting my newObj will become
data = {
'id':'123',
'employeeName': 'John',
'employeeType': 'new'
}
after I ran the codes above, it still stays the same as it was like
data = {
'id':'123',
'employee_name': 'John',
'employee_type': 'new'
}
This is super weird and I'm not sure what went wrong. Can someone help me about this? Thanks a lot!
replacing snake_case or kebab-case to camelCase only for string (ES6+):
const snakeToCamel = str =>
str.toLowerCase().replace(/([-_][a-z])/g, group =>
group
.toUpperCase()
.replace('-', '')
.replace('_', '')
);
result:
console.log(snakeToCamel('TO_CAMEL')) //toCamel
console.log(snakeToCamel('to_camel')) //toCamel
console.log(snakeToCamel('TO-CAMEL')) //toCamel
console.log(snakeToCamel('to-camel')) //toCamel
Use _.mapKeys() instead of _.mapValues():
var data = {
'id': '123',
'employee_name': 'John',
'employee_type': 'new'
};
var newObj = _.mapKeys(data, (value, key) => _.camelCase(key));
console.log('newObj: ', newObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
If you need to ignore the redundant value param, you can use _.rearg() on _.camelCase() to generate a function that takes the 2nd param (the key) instead of the 1st param (the value).
var data = {
'id': '123',
'employee_name': 'John',
'employee_type': 'new'
};
var newObj = _.mapKeys(data, _.rearg(_.camelCase, 1));
console.log('newObj: ', newObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
You can also easily create your own function for that:
function camelCase(obj) {
var newObj = {};
for (d in obj) {
if (obj.hasOwnProperty(d)) {
newObj[d.replace(/(\_\w)/g, function(k) {
return k[1].toUpperCase();
})] = obj[d];
}
}
return newObj;
}
var data = {
'id': '123',
'employee_name': 'John',
'employee_type': 'new'
}
console.log(camelCase(data));
Here's how to do it in native Javascript...
let data = {
'id':'123',
'employee_name': 'John',
'employee_type': 'new'
}
// #1 simple function which converts a string from snake case to camel case ...
const snakeToCamel = s => s.replace(/(_\w)/g, k => k[1].toUpperCase())
// #2 create new data object with camelCase keys...
data = Object.entries(data).reduce((x,[k,v]) => (x[snakeToCamel(k)]=v) && x, {})
console.log(data)
For my use case I needed (or wanted) a function that would handle any arbitrary json object, including nested objects, arrays, etc. Came up with this, seems to be working so far:
const fromSnakeToCamel = (data) => {
if (_.isArray(data)) {
return _.map(data, fromSnakeToCamel);
}
if (_.isObject(data)) {
return _(data)
.mapKeys((v, k) => _.camelCase(k))
.mapValues((v, k) => fromSnakeToCamel(v))
.value();
}
return data;
}
Note that if it's not an array or an object, I just return the data because I only actually want to convert keys. Anyway, hope this helps someone
These are all good answers, but they did not fit what I needed. I like Ashish's answer because it handles nested objects, but what if there are underscores in the data that you want? So, here is a varient on Bambam's answer to make it recursive, because lodash can sometimes be a pain.
function toCamelCase (obj) {
let rtn = obj
if(!rtn) {
return rtn
} else if (typeof (obj) === 'object') {
if (obj instanceof Array) {
rtn = obj.map(toCamelCase)
} else {
rtn = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const newKey = key.replace(/(_\w)/g, k => k[1].toUpperCase())
rtn[newKey] = toCamelCase(obj[key])
}
}
}
}
return rtn
}
TypeScript
As always, nobody asked for typescript version, but here it is, please don't beat me ^-^.
Without _, No RegExp
I split functions in two modules but you can keep them outside with proper naming
I put never to mark out that the type is actually correct since TS doesn't always know if it is.
You still can use _ and get code shorter but I wanted to breakdown the process.
module CaseTransform {
export type Snake = Lowercase<`${string}_${string}`>
export type Camel = Capitalize<string> | `${Capitalize<string>}${Capitalize<string>}`
export type SnakeToCamel<S extends string> = S extends `${infer Start}_${infer Rest}` ? `${Start}${Capitalize<SnakeToCamel<Rest>>}` : S
type SnakeToCamel__TEST__ = SnakeToCamel<"my_account_profile"> // myAccountProfile
export function capitalize<S extends string>(string: S): Capitalize<S> {
if (string.length === 0) return "" as never
return (string[0].toUpperCase() + string.slice(1)) as never
}
export function snakeToCamel<S extends string>(string: S): SnakeToCamel<S> {
const [start, ...rest] = string.split("_")
return (start + rest.map(capitalize)) as never
}
const snakeToCamel__TEST__ = snakeToCamel("ASD_asd_asdad_")
}
module ObjectTransform {
export function snakeToCamel<O extends object, K extends keyof O>(object: O): { [P in K as (P extends CaseTransform.Snake ? CaseTransform.SnakeToCamel<P> : P)]: O[P] } {
return Object
.entries(object)
.reduce((result, [key, value]) => ({
...result,
[CaseTransform.snakeToCamel(key)]: value
}), {}) as never
}
}
const sample = {
id: 123,
employee_name: "John",
employee_type: "new",
camelCase: "123",
PascalCase: "123"
}
const __TEST__ = ObjectTransform.snakeToCamel(sample)
Note
If you want all characters (even abbreviations) to be in lowercase, put .toLowercase() after string AND change SnakeToCamel type to
type SnakeToCamel<S extends string> = S extends `${infer Start}_${infer Rest}` ? `${Lowercase<Start>}${Capitalize<SnakeToCamel<Rest>>}` : Lowercase<S>
Easy!
Typings Result
JavaScript Playground
function capitalize(string) {
if (string.length === 0) return ""
return (string[0].toUpperCase() + string.slice(1))
}
function snakeToCamel(string){
const [start, ...rest] = string.split("_")
return (start + rest.map(capitalize).join(""))
}
const snakeToCamel__TEST__ = snakeToCamel("ASD_asd_asdad_")
console.log(snakeToCamel__TEST__)
function objectKeysSnakeToCamel(object) {
return Object
.entries(object)
.reduce((result, [key, value]) => ({
...result,
[snakeToCamel(key)]: value
}), {})
}
const sample = {
id: 123,
employee_name: "John",
employee_type: "new",
camelCase: "123",
PascalCase: "123"
}
const __TEST__ = objectKeysSnakeToCamel(sample)
console.log(__TEST__)
Here is another answer using simple for loop.
var data = {
'id': '123',
'employee_name': 'John',
'employee_type': 'new'
};
var output = {}
for (var key in data) {
output[_.camelCase(key)] = data[key];
}
Try this it will definitely work as expected.
const helpers = {};
helpers.camelize = function(str) {
return str.trim().replace(/[A-Z]+/g, (letter, index) => {
return index == 0 ? letter.toLowerCase() : '_' + letter.toLowerCase();
}).replace(/(.(\_|-|\s)+.)/g, function(subStr) {
return subStr[0]+(subStr[subStr.length-1].toUpperCase());
});
}
helpers.camelizeKeys = function(data) {
const result = {};
for (const [key, val] of Object.entries(data)) {
result[helpers.camelize(key)] = val;
}
return result;
}
helpers.camelizeNestedKeys = function(dataObj) {
return JSON.parse(JSON.stringify(dataObj).trim().replace(/("\w+":)/g, function(keys) {
return keys.replace(/[A-Z]+/g, (letter, index) => {
return index == 0 ? letter.toLowerCase() : '_' + letter.toLowerCase();
}).replace(/(.(\_|-|\s)+.)/g, function(subStr) {
return subStr[0]+(subStr[subStr.length-1].toUpperCase());
});
}));
}
const data = {
'id':'123',
'employee_name': 'John',
'employee_type': 'new'
};
const nestedData = {
'id':'123',
'employee_name': 'John',
'employee_type': 'new',
'exployee_projects': [
{"project_name": "test1", "project_year": 2004},
{"project_name": "test2", "project_year": 2004}
]
};
// Few camelize Examples
const str1 = "banana_orange_apple_mango";
const str2 = "banana-orange-apple-mango";
const str3 = "banana orange apple mango";
const str4 = "BANANA Orange APPLE-mango";
const str5 = "banana 5orange apple #mango";
const str6 = "banana__orange-_apple5-#mango";
console.log(helpers.camelize(str1));
console.log(helpers.camelize(str2));
console.log(helpers.camelize(str3));
console.log(helpers.camelize(str4));
console.log(helpers.camelize(str5));
console.log(helpers.camelize(str6));
console.log("=============================");
// camelize object keys
console.log(helpers.camelizeKeys(data));
console.log("=============================");
// camelize nested object keys
console.log(helpers.camelizeNestedKeys(nestedData));
If you want to convert the nested object, then using lodash can be a bit painful.
I tried using regex, JSON.parse & JSON.stringify
and here is the code for the same
below code returns the new object that is having camel case instead of snake case
//input
var data = {
'id': '123',
'employee_name': 'John',
'employee_type': {'new_name': 'foo'}
};
JSON.parse(JSON.stringify(data).replace(
/(_\w)\w+":/g,
match => match[1].toUpperCase() + match.substring(2)
));
{
'id': '123',
'employeeName': 'John',
'employeeType': {'newName': 'foo'}
}
Based on Abbos Tajimov's answer (and Ali's comment), we could also take advantage of the arguments passed down to the inline function.
const snakeToCamel = str => {
if (!(/[_-]/).test(str)) return str
return str.toLowerCase()
.replace(/([-_])([a-z])/g, (_match, _p1, p2) => p2.toUpperCase())
}
camelCase(str) {
return str
.toLowerCase()
.replace(/([-_][a-z])/g, (ltr) => ltr.toUpperCase())
.replace(/[^a-zA-Z]/g, '')
}
another way
_(data)
.keys()
.map(_.camelCase)
.zipObject(_.values(data))
.value()
I really like Mardok's version with nested objects, only issue is that it converts "null" to {}
here mine:
import _ from 'lodash';
export const toCamelCase: any = (obj: any) => {
let rtn = obj
if (typeof obj === 'object') {
if (obj instanceof Array) {
rtn = obj.map(toCamelCase)
}
else if (_.isEmpty(obj)) {
rtn = null
} else {
rtn = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const newKey = key.replace(/(_\w)/g, k => k[1].toUpperCase())
rtn[newKey] = toCamelCase(obj[key])
}
}
}
}
return rtn
}
Creates camelized object recursively.
function camelCase(obj) {
const newObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
const keyCamel = key.replace(/(\_\w)/g, (match) => match[1].toUpperCase());
const isRecursive = typeof value === 'object';
newObj[keyCamel] = isRecursive ? camelCase(value) : value;
}
}
return newObj;
}
let data = {
id: '123',
employee_name: 'John',
inner: {
employee_type: 'new'
},
}
camelCase(data);
Found in typeorm repo https://github.com/typeorm/typeorm/blob/master/src/util/StringUtils.ts#L8
export function camelCase(str: string, firstCapital: boolean = false): string {
return str.replace(
/^([A-Z])|[\s-_](\w)/g,
function (match, p1, p2, offset) {
if (firstCapital === true && offset === 0) return p1
if (p2) return p2.toUpperCase()
return p1.toLowerCase()
},
)
}
Use npm json-case-handler which will allow you to do this in one line.
It can convert any nested objects
For your case, you can do this :
const jcc = require('json-case-convertor')
const snakeCasedJson = jcc.snakeCaseKeys(yourjsonData)
Just pass the value to input and the result will be camelcase:
const snakeToCamel = input =>
console.log(
input.slice(0, input.indexOf('_')).toLowerCase() +
input[input.indexOf('_') + 1].toUpperCase() +
input.slice(input.indexOf('_') + 2)
);
const inputs = [
'underscore_case',
'first_name',
'Some_Variable',
'calculate_AGE',
'delayed_departure',
'Hello_you',
'hAI_i',
];
for (let input of inputs) {
snakeToCamel(input);
}
This function will recursively convert all snake case keys in the object to camelCase. Including objects within arrays and object within objects.
const convertSnakeCaseToCamelCase = (obj) => {
let newObj = {};
if (typeof(obj) !== 'object') {
return obj;
} else if (Array.isArray(obj)) {
newObj = [];
}
for (const key in obj) {
const childObj = convertSnakeCaseToCamelCase(obj[key]);
if (Array.isArray(obj)) {
newObj.push(childObj);
} else {
const newKey = key.replace(/(\_\w)/g, (k) => k[1].toUpperCase());
newObj[newKey] = childObj;
}
}
return newObj;
};

Categories