Trying to extract common functionality among these - javascript

I have below method where i am using reducer to set these dictionaries "earliestOptionByInitialRevision" and "latestOptionByInitialRevision" inside the reducer and the code is looks like as below
const lookups = optionsInput?.reduce(
(acc, option) => {
const [optionById, earliestOptionByInitialRevision, latestOptionByInitialRevision] = acc;
optionById[option.id] = option;
const isCustomProject = option.initialRevisionId === null || option.initialRevisionId === undefined;
if (
isCustomProject ||
!earliestOptionByInitialRevision[option.initialRevisionId] ||
option.revision < earliestOptionByInitialRevision[option.initialRevisionId].revision
) {
// trying to extract the below into common
//function because in below if condition i have used the same and difference is
// "earliestOptionByInitialRevision"
if (isCustomProject) {
option = {...option, initialRevisionId:'customProjectOption'}
if (!earliestOptionByInitialRevision[option.initialRevisionId])
{
earliestOptionByInitialRevision[option.initialRevisionId] = [option];
} else {
earliestOptionByInitialRevision[option.initialRevisionId].push(option);
}
} else {
earliestOptionByInitialRevision[option.initialRevisionId] = option;
}
}
if (
isCustomProject ||
!latestOptionByInitialRevision[option.initialRevisionId] ||
option.revision > latestOptionByInitialRevision[option.initialRevisionId].revision
) {
// the below if condition same as with above and the difference
// is "latestOptionByInitialRevision"
if (isCustomProject) {
option = {...option, initialRevisionId:'customProjectOption'}
if (!latestOptionByInitialRevision[option.initialRevisionId]) {
latestOptionByInitialRevision[option.initialRevisionId] = [option];
} else {
latestOptionByInitialRevision[option.initialRevisionId].push(option);
}
} else {
latestOptionByInitialRevision[option.initialRevisionId] = option;
}
}
return acc;
},
[{}, {}, {}]
) ?? [{}, {}, {}];
const [optionById, earliestOptionByInitialRevision, latestOptionByInitialRevision] = lookups;
i would like to extract the below common functionality but could not be able to get through on how to achieve the same. Could any one please help on this that would be very grateful to me
if (isCustomProject) {
option = {...option, initialRevisionId:'customProjectOption'}
if (!earliestOptionByInitialRevision[option.initialRevisionId]) {
earliestOptionByInitialRevision[option.initialRevisionId] = [option];
} else {
earliestOptionByInitialRevision[option.initialRevisionId].push(option);
}
} else {
earliestOptionByInitialRevision[option.initialRevisionId] = option;
}
Many thanks in advance
update:

A quick fix could be to extract the common functionality into a function, parameterised by the dict (JavaScript object).
const optionsInput = [{
id: 1,
revision: 2
},
{
id: 2,
revision: 1
},
];
const lookups = optionsInput?.reduce(
(acc, option) => {
const [optionById, earliestOptionByInitialRevision, latestOptionByInitialRevision] = acc;
optionById[option.id] = option;
const isCustomProject = option.initialRevisionId === null || option.initialRevisionId === undefined;
const updateDict = (dict) => {
if (isCustomProject) {
const newOption = {...option, initialRevisionId:'customProjectOption'}
if (!dict[option.initialRevisionId]) {
dict[option.initialRevisionId] = [newOption];
} else {
dict[option.initialRevisionId].push(newOption);
}
} else {
dict[option.initialRevisionId] = option;
}
};
if (isCustomProject || !earliestOptionByInitialRevision[option.initialRevisionId] || option.revision < earliestOptionByInitialRevision[option.initialRevisionId].revision) {
updateDict(earliestOptionByInitialRevision);
}
if (isCustomProject || !latestOptionByInitialRevision[option.initialRevisionId] || option.revision > latestOptionByInitialRevision[option.initialRevisionId].revision) {
updateDict(latestOptionByInitialRevision);
}
return acc;
},
[{}, {}, {}]
) ?? [{}, {}, {}];
console.log(lookups);

Related

find the json path for a specific value using javascript

how to find the json path for a specific value using javascript
var data = {
key1: {
children: {
key2:'value',
key3:'value',
key4: value
},
key5: 'value'
}
expected result from the above data.key1.children.key3
Any help would be appreciated.
var str = "key3";
data["key1"]["children"][str];
This function returns all available paths in your(any) object:
Using this function you can get
["key1.children.key2", "key1.children.key3", "key1.children.key4", "key1.key5"]
function allPaths(root) {
let stack = [];
let result = [];
// checks if object
const isObject = value => typeof value === "object";
stack.push(root);
while (stack.length > 0) {
let node = stack.pop();
if (isObject(node)) {
Object.entries(node).forEach(([childNodeKey, childNodeValue]) => {
if (isObject(childNodeValue)) {
const newObject = Object.fromEntries(
Object.entries(childNodeValue).map(([cnk, cnv]) => {
return [`${childNodeKey}.${cnk}`, cnv];
})
);
stack.push(newObject);
} else {
stack.push(`${childNodeKey}`);
}
})
} else {
result.push(node);
}
}
return result.reverse();
}
Let me know in the comments if it was helpful for you

Double for loop without mutating prop, VUE3

I have a 'data' props which say looks like this:
data = [
{
"label":"gender",
"options":[
{"text":"m","value":0},
{"text":"f","value":1},
{"text":"x", "value":null}
]
},
{
"label":"age",
"options":[
{"text":"<30", "value":0},
{"text":"<50","value":1},
{"text":">50","value":3}
]
}
]
In a computed property I want to have a new array which looks exactly like the data prop, with the difference that - for the sake of example let's say - I want to multiply the value in the options array by 2. In plain js I did this before, like this:
data.forEach(item => {
item.options.forEach(option => {
if (option.value !== null && option.value !== 0) {
option.value *= 2;
}
})
});
Now I'm trying to do this in a computed property, with .map(), so it doesn't mutate my data props, but I cant figure out how.
computed: {
doubledValues() {
var array = this.data.map((item) => {
//...
item.options.map((option) => {
//... option.value * 2;
});
});
return array;
}
}
you can use map() method, like so:
computed: {
doubledValues() {
return this.data.map(item => ({...item, options: item.options.map(obj => {
return (obj.value != null) ? { ...obj, value: obj.value * 2 } : { ...obj }
})})
);
}
}
Just copy objects/arrays. It will be something like that
computed: {
doubledValues() {
return this.data.map((item) => {
const resultItem = {...item};
resultItem.options = item.options.map((option) => {
const copyOption = {...option};
if (copyOption.value !== null && copyOption.value !== 0) {
copyOption.value *= 2;
}
return copyOption;
});
return resultItem;
});
}
}

How to remove empty nested objects in an array?

I have an array of objects, that can either have direct or nested values. The goal is to remove all empty fields.
For exemple:
const todos = [ {}, { not: {} } ]
// expected output: []
const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ]
// expected output: [{ not: {countries: ["uk", "us"]} }]
I've tried to filter the array with Object.values.length, it when a nested value is an empty object, it doesn't work anymore. Would someone know how to do it?
EDIT: So I've came up with my own solution which is a bit simpler from what I've read here:
function foo(todos){
todos.map((todo,i)=> {
if(!Object.keys(todo).length){
return todos.splice(i, 1)
}
if(Object.keys(todo).length){
const key = Object.keys(todo) + ""
return !Object.values(todo[key]).length && todos.splice(i, 1)
}
return todo
})
return todos.filter(c=> Object.keys(c).length)
}
Because your structure has a mix of Objects and Arrays, you will want to check for this.
Below is an example.
function trimEmptyObjects(o) {
if (typeof o !== 'object') return o;
if (Array.isArray(o)) {
for (let i = o.length -1; i >= 0; i --) {
o[i] = trimEmptyObjects(o[i]);
if (typeof o[i] === 'object') {
if (!Object.keys(o[i]).length) {
o.splice(i, 1);
}
}
}
return o;
} else {
const e = Object.entries(o);
for (let i = e.length -1; i >= 0; i --) {
e[i][1] = trimEmptyObjects(e[i][1]);
if (typeof e[i][1] === 'object') {
if (!Object.keys(e[i][1]).length) {
e.splice(i, 1);
}
}
}
return Object.fromEntries(e);
}
}
const todos = [ {}, { not: {} } ]
// expected output: []
console.log(trimEmptyObjects(todos));
const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ]
// expected output: [{ not: {countries: ["uk", "us"]} }]
console.log(trimEmptyObjects(todos2));
I think you want like this..
const todos = [ {}, { not: {} } ];
const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ];
function clean(object) {
Object
.entries(object)
.forEach(([k, v]) => {
if (v && typeof v === 'object') {
clean(v);
}
if (v && typeof v === 'object' && !Object.keys(v).length || v === null || v === undefined) {
if (Array.isArray(object)) {
object.splice(k, 1);
} else {
delete object[k];
}
}
});
return object;
}
console.log(clean(todos));
console.log(clean(todos2));
try with filter
const isEmpty = e => Object.entries(e).length
const removeEmptyObject = e => e.not?isEmpty(e.not):isEmpty(e)
const todos = [ {}, { not: {} } ]
console.log(todos.filter(removeEmptyObject))
const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ]
console.log(todos2.filter(removeEmptyObject))

Javascript: More concise way to reduce/aggregate by key?

This code gives the expected result, but is there a more concise way to achieve the same result? This is simply a matter of curiosity though.
The goal is to have a map representing the total students in each school, as well as a map representing the total teachers in each school.
// Example data
const studentsMap = {
student123: {
teacher: 'teacher123'
},
student456: {
teacher: 'teacher123'
},
student789: {
teacher: 'badID'
},
student000: {}
};
const teachersMap = {
teacher123: {
school: 'school123'
},
teacher456: {
school: 'school123'
},
teacher789: {
school: 'school456'
}
};
const studentsTotalBySchool = Object.keys(studentsMap).reduce((totals, key) => {
const current = studentsMap[key];
if (!teachersMap[current.teacher] || !teachersMap[current.teacher].school) {
return totals;
}
totals[teachersMap[current.teacher].school] = (totals[teachersMap[current.teacher].school] || 0) + 1;
return totals;
}, {});
const teachersTotalBySchool = Object.keys(teachersMap).reduce((totals, key) => {
const current = teachersMap[key];
totals[current.school] = (totals[current.school] || 0) + 1;
return totals;
}, {});
Is there a way to write this more succinctly without sacrificing too much readability?
You can use Object.entries and destructuring like so:
const studentsTotalBySchool = Object.entries(studentsMap).reduce((totals, [key, { teacher }) => {
if (!teachersMap[teacher] || !teachersMap[teacher].school) return totals;
totals[teachersMap[teacher].school] = (totals[teachersMap[teacher].school] || 0) + 1;
return totals;
}, {});
const teachersTotalBySchool = Object.entries(teachersMap).reduce((totals, [key, { school }) => {
totals[school] = (totals[school] || 0) + 1;
return totals;
}, {});
this will get you the same results with much less code
let schools = {
school123: {
teacher123 : {
students: ["student123", "student456"]
},
teacher456 : {
students: ["student789"]
}
},
school456: {
teacher123 : {
students: ["student123", "student456"]
},
teacher456 : {
students: ["student789"]
}
}
};
function findTotal(school, totalOf){
let accumulated = 0;
switch(totalOf){
case "students":
for(let teachers of Object.keys(schools[school])){
accumulated += schools[school][teachers].students.length;
}
break;
case "teachers":
accumulated = Object.keys(schools[school]).length;
}
return accumulated;
}
console.log(findTotal("school123", "students"))
console.log(findTotal("school123", "teachers"))

Convert returned JSON Object Properties to (lower first) camelCase

I have JSON returned from an API like so:
Contacts: [{ GivenName: "Matt", FamilyName: "Berry" }]
To keep this consistent with my code style (camelCase - lower case first letter) I want to transform the array to produce the following:
contacts: [{ givenName: "Matt", familyName: "Berry" }]
What's the easiest/best way to do this? Create a new Contact object and iterate over all the contacts in the returned array?
var jsonContacts = json["Contacts"],
contacts= [];
_.each(jsonContacts , function(item){
var contact = new Contact( item.GivenName, item.FamilyName );
contacts.push(contact);
});
or can I map the original array or transform it somehow?
If you would use lodash instead of underscore, this would do:
_.mapKeys(obj, (v, k) => _.camelCase(k))
This would convert both TitleCase and snake_case to camelCase. Note that it is not recursive though.
Here's a reliable, recursive function that will properly camelCase all of a JavaScript object's properties:
function toCamel(o) {
var newO, origKey, newKey, value
if (o instanceof Array) {
return o.map(function(value) {
if (typeof value === "object") {
value = toCamel(value)
}
return value
})
} else {
newO = {}
for (origKey in o) {
if (o.hasOwnProperty(origKey)) {
newKey = (origKey.charAt(0).toLowerCase() + origKey.slice(1) || origKey).toString()
value = o[origKey]
if (value instanceof Array || (value !== null && value.constructor === Object)) {
value = toCamel(value)
}
newO[newKey] = value
}
}
}
return newO
}
Test:
var obj = {
'FirstName': 'John',
'LastName': 'Smith',
'BirthDate': new Date(),
'ArrayTest': ['one', 'TWO', 3],
'ThisKey': {
'This-Sub-Key': 42
}
}
console.log(JSON.stringify(toCamel(obj)))
Output:
{
"firstName":"John",
"lastName":"Smith",
"birthDate":"2017-02-13T19:02:09.708Z",
"arrayTest": [
"one",
"TWO",
3
],
"thisKey":{
"this-Sub-Key":42
}
}
You can do this with this recursive function (with lodash and ES6):
import { camelCase } from 'lodash';
const camelizeKeys = (obj) => {
if (Array.isArray(obj)) {
return obj.map(v => camelizeKeys(v));
} else if (obj != null && obj.constructor === Object) {
return Object.keys(obj).reduce(
(result, key) => ({
...result,
[camelCase(key)]: camelizeKeys(obj[key]),
}),
{},
);
}
return obj;
};
Test:
const obj = {
'FirstName': 'John',
'LastName': 'Smith',
'BirthDate': new Date(),
'ArrayTest': ['one', 'TWO', 3],
'ThisKey': {
'This-Sub-Key': 42
}
}
console.log(JSON.stringify(camelizeKeys(obj)))
Output:
{
"firstName": "John",
"lastName": "Smith",
"birthDate": "2018-05-31T09:03:57.844Z",
"arrayTest":[
"one",
"TWO",
3
],
"thisKey":{
"thisSubKey": 42
}
}
To change a plain object's keys from snake_case to camelCase recursively try the following
(which uses Lodash):
function objectKeysToCamelCase(snake_case_object) {
var camelCaseObject = {};
_.forEach(
snake_case_object,
function(value, key) {
if (_.isPlainObject(value) || _.isArray(value)) { // checks that a value is a plain object or an array - for recursive key conversion
value = objectKeysToCamelCase(value); // recursively update keys of any values that are also objects
}
camelCaseObject[_.camelCase(key)] = value;
}
)
return camelCaseObject;
};
test in this PLUNKER
Note: also works recursively for objects within arrays
Using lodash and ES6, this will replace all keys recursively to camelcase:
const camelCaseKeys = (obj) => {
if (!_.isObject(obj)) {
return obj;
} else if (_.isArray(obj)) {
return obj.map((v) => camelCaseKeys(v));
}
return _.reduce(obj, (r, v, k) => {
return {
...r,
[_.camelCase(k)]: camelCaseKeys(v)
};
}, {});
};
Just use humps
humps.camelize('hello_world');
humps.camelizeKeys(object, options); // will work through entire object
https://www.npmjs.com/package/humps
This is a great use case for axios interceptors
Basically, define a client class and attach a before/after interceptor that converts the request/response data.
export default class Client {
get(url, data, successCB, catchCB) {
return this._perform('get', url, data, successCB, catchCB);
}
post(url, data, successCB, catchCB) {
return this._perform('post', url, data, successCB, catchCB);
}
_perform(method, url, data, successCB, catchCB) {
// https://github.com/axios/axios#interceptors
// Add a response interceptor
axios.interceptors.response.use((response) => {
response.data = toCamelCase(response.data);
return response;
}, (error) => {
error.data = toCamelCase(error.data);
return Promise.reject(error);
});
// Add a request interceptor
axios.interceptors.request.use((config) => {
config.data = toSnakeCase(config.data);
return config;
}, (error) => {
return Promise.reject(error);
});
return axios({
method: method,
url: API_URL + url,
data: data,
headers: {
'Content-Type': 'application/json',
},
}).then(successCB).catch(catchCB)
}
}
Here's a gist with a longer example using React/axios.
there's a nice npm module for this..
https://www.npmjs.com/package/camelcase-keys
npm install camelcase-keys
const camelcaseKeys = require( "camelcase-keys" );
camelcaseKeys( { Contacts: [ { GivenName: "Matt", FamilyName: "Berry" } ] }, { deep: true } );
will return...
{ contacts: [ { givenName: "Matt", familyName: "Berry" } ] }
This solution based on the plain js solution above, uses loadash and Keeps an array if passed as a parameter and Only change the Keys
function camelCaseObject(o) {
let newO, origKey, value
if (o instanceof Array) {
newO = []
for (origKey in o) {
value = o[origKey]
if (typeof value === 'object') {
value = camelCaseObject(value)
}
newO.push(value)
}
} else {
newO = {}
for (origKey in o) {
if (o.hasOwnProperty(origKey)) {
newO[_.camelCase(origKey)] = o[origKey]
}
}
}
return newO
}
// Example
const obj = [
{'my_key': 'value'},
{'Another_Key':'anotherValue'},
{'array_key':
[{'me_too':2}]
}
]
console.log(camelCaseObject(obj))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Using lodash, you can do it like this:
export const toCamelCase = obj => {
return _.reduce(obj, (result, value, key) => {
const finalValue = _.isPlainObject(value) || _.isArray(value) ? toCamelCase(value) : value;
return { ...result, [_.camelCase(key)]: finalValue };
}, {});
};
Well I took up the challenge and think I figured it out:
var firstToLower = function(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
};
var firstToUpper = function(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
var mapToJsObject = function(o) {
var r = {};
$.map(o, function(item, index) {
r[firstToLower(index)] = o[index];
});
return r;
};
var mapFromJsObject = function(o) {
var r = {};
$.map(o, function(item, index) {
r[firstToUpper(index)] = o[index];
});
return r;
};
// Map to
var contacts = [
{
GivenName: "Matt",
FamilyName: "Berry"
},
{
GivenName: "Josh",
FamilyName: "Berry"
},
{
GivenName: "Thomas",
FamilyName: "Berry"
}
];
var mappedContacts = [];
$.map(contacts, function(item) {
var m = mapToJsObject(item);
mappedContacts.push(m);
});
alert(mappedContacts[0].givenName);
// Map from
var unmappedContacts = [];
$.map(mappedContacts, function(item) {
var m = mapFromJsObject(item);
unmappedContacts.push(m);
});
alert(unmappedContacts[0].GivenName);
Property converter (jsfiddle)
The trick is handling the objects as arrays of object properties.
Here's handy library you might wanna try:
https://www.npmjs.com/package/camelize2
You simply need to install it with npm install --save camelize2 and then
const camelize = require('camelize2')
const response = {
Contacts: [{ GivenName: "Matt", FamilyName:"Berry" }]
}
const camelizedResponse = camelize(response)
Solution similar to #brandonscript, but in more ES6-functional way:
const camelCaseString = str => (
(str.charAt(0).toLowerCase() + str.slice(1) || str).toString()
);
const objectToCamelCase = val => {
if (typeof val != 'object' || val === null) {
return val;
}
if (val instanceof Array) {
return val.map(objectToCamelCase);
}
return Object.keys(val)
.filter(prop => val.hasOwnProperty(prop))
.map(prop => ({[camelCaseString(prop)]: objectToCamelCase(val[prop])}))
.reduce((prev, current) => ({...prev, ...current}))
};
// Example:
let converted = objectToCamelCase({UserId: 1, Hobbies: [{Id: 1, Label: "Read"}], Name: "John Doe"});
console.log(converted)
I needed a generic method that accepted an array or object. This is what I'm using (I borrowed KyorCode's firstToLower() implementation):
function convertKeysToCamelCase(obj) {
if (!obj || typeof obj !== "object") return null;
if (obj instanceof Array) {
return $.map(obj, function(value) {
return convertKeysToCamelCase(value);
});
}
var newObj = {};
$.each(obj, function(key, value) {
key = key.charAt(0).toLowerCase() + key.slice(1);
if (typeof value == "object" && !(value instanceof Array)) {
value = convertKeysToCamelCase(value);
}
newObj[key] = value;
});
return newObj;
};
Example calls:
var contact = { GivenName: "Matt", FamilyName:"Berry" };
console.log(convertKeysToCamelCase(contact));
// logs: Object { givenName="Matt", familyName="Berry"}
console.log(convertKeysToCamelCase([contact]));
// logs: [Object { givenName="Matt", familyName="Berry"}]
console.log(convertKeysToCamelCase("string"));
// logs: null
console.log(contact);
// logs: Object { GivenName="Matt", FamilyName="Berry"}
Took the challenge with lodash and some es6+ features
Here is my implementation with the reduce function.
function deeplyToCamelCase(obj) {
return _.reduce(obj, (camelCaseObj, value, key) => {
const convertedDeepValue = _.isPlainObject(value) || _.isArray(value)
? deeplyToCamelCase(value)
: value;
return { ...camelCaseObj, [_.camelCase(key)] : convertedDeepValue };
}, {});
};
Use lodash ...
function isPrimitive (variable) {
return Object(variable) !== variable
}
function toCamel (variable) {
if (isPrimitive(variable)) {
return variable
}
if (_.isArray(variable)) {
return variable.map(el => toCamel(el))
}
const newObj = {}
_.forOwn(variable, (value, key) => newObj[_.camelCase(key)] = toCamel(value))
return newObj
}
This function loop recursively through the object keys and using lodash returns a new object with every field converted to camelCase. It works also with arrays, nested arrays, nested objects.
function deepCamelCase (obj) {
const c = {}
if (typeof obj !== 'object') return obj
_.mapKeys(obj, (v, k) => {
let w = {}
if (typeof v === 'object') {
if (Array.isArray(v)) {
const k = []
for (const i of v) {
k.push(deepCamelCase(i))
}
} else {
_.mapValues(v, (n, m) => {
if (Array.isArray(n)) {
const k = []
for (const i of n) {
k.push(deepCamelCase(i))
}
w[_.camelCase(m)] = k
} else {
w[_.camelCase(m)] = deepCamelCase(n)
}
})
}
} else {
w = v
}
c[_.camelCase(k)] = w
})
return c
}
Updated code using the reference from https://plnkr.co/edit/jtsRo9yU12geH7fkQ0WL?p=preview
This handles the Objects with array with objects inside it too and so on, by keeping arrays as arrays (which you can iterate over using map)
function snakeToCamelCase(snake_case_object){
var camelCaseObject;
if (isPlainObject(snake_case_object)) {
camelCaseObject = {};
}else if(isArray(snake_case_object)){
camelCaseObject = [];
}
forEach(
snake_case_object,
function(value, key) {
if (isPlainObject(value) || isArray(value)) {
value = snakeToCamelCase(value);
}
if (isPlainObject(camelCaseObject)) {
camelCaseObject[camelCase(key)] = value;
}else if(isArray(camelCaseObject)){
camelCaseObject.push(value);
}
}
)
return camelCaseObject;
}
This is my take; more readable and with less nesting than brandoncode's implementation, and with more room for handling edge cases like Date (which isn't handled, by the way) or null:
function convertPropertiesToCamelCase(instance) {
if (instance instanceof Array) {
var result = [];
for (var i = 0; i < instance.length; i++) {
result[i] = convertPropertiesToCamelCase(instance[i]);
}
return result;
}
if (typeof instance != 'object') {
return instance;
}
var result = {};
for (var key in instance) {
if (!instance.hasOwnProperty(key)) {
continue;
}
result[key.charAt(0).toLowerCase() + key.substring(1)] = convertPropertiesToCamelCase(instance[key]);
}
return result;
}
Building on goredwards answer (which didn't handle the array fields correctly)
function objectKeysToCamelCase(snake_case_object) {
let camelCaseObject = {}
_.forEach(
snake_case_object,
function(value, key) {
if (_.isPlainObject(value)) {
value = objectKeysToCamelCase(value)
} else if (_.isArray(value)) {
value = value.map(v => _.isPlainObject(v) ? objectKeysToCamelCase(v) : v)
}
camelCaseObject[_.camelCase(key)] = value
},
)
return camelCaseObject
}
here is code I found for it, not fully tested though, but worth sharing.
It is far more readable than other answers, not sure about performance.
test it http://jsfiddle.net/ms734bqn/1/
const toCamel = (s) => {
return s.replace(/([-_][a-z])/ig, ($1) => {
return $1.toUpperCase()
.replace('-', '')
.replace('_', '');
});
};
const isArray = function (a) {
return Array.isArray(a);
};
const isObject = function (o) {
return o === Object(o) && !isArray(o) && typeof o !== 'function';
};
const keysToCamel = function (o) {
if (isObject(o)) {
const n = {};
Object.keys(o)
.forEach((k) => {
n[toCamel(k)] = keysToCamel(o[k]);
});
return n;
} else if (isArray(o)) {
return o.map((i) => {
return keysToCamel(i);
});
}
return o;
};
Pure JavaScript, shoud work fine
function convertKeysToCamelCase(object) {
if(object === undefined || object === null || typeof object !== "object") {
return object;
} else {
if(Array.isArray(object)) {
return object.map(item => convertKeysToCamelCase(item));
} else {
return Object.entries(object).reduce((result, [key, value]) => {
result[key.charAt(0).toLowerCase() + key.slice(1)] = convertKeysToCamelCase(value);
return result;
}, {});
}
}
}
you can do this simply by using json-case-convertor
const jcc = require('json-case-convertor')
const jsonData = ''//you json data to convert
const camelCasedJson = jcc.camelCaseKeys(jsonData) //Convert all the keys of object to snake case
This will handle all cascaded object as well
Convert object keys to camelCase with deep.
import _ from 'lodash';
export function objectKeysToCamelCase(entity) {
if (!_.isObject(entity)) return entity;
let result;
result = _.mapKeys(entity, (value, key) => _.camelCase(key));
result = _.mapValues(result, (value) => objectKeysToCamelCase(value));
return result;
}

Categories