You can simply use the npm package flat.
import flat from 'flat';
const array = [
{
a: 'a',
b: {
bb: 'bb',
},
c: {
cc1: 'cc1',
cc: {
ccc: 'ccc',
ccd: 'ccd',
},
},
},
// ...
];
const flattenedArray = array.map(flat);
/*
flattenedArray === [
{
a: 'a',
b.bb: 'bb',
c.cc1: 'cc1',
c.cc.ccc: 'ccc',
c.cc.ccd: 'ccd',
},
// ...
]
*/
And if you want to implement it yourself, here's my implementation of flat:
const flat = (obj, concatenator = '.') => (
Object.keys(obj).reduce(
(acc, key) => {
if (typeof obj[key] !== 'object' || !obj[key]) {
return {
...acc,
[key]: obj[key],
};
}
const flattenedChild = flat(obj[key], concatenator);
return {
...acc,
...Object.keys(flattenedChild).reduce((childAcc, childKey) => ({ ...childAcc, [`
{concatenator}${childKey}`]: flattenedChild[childKey] }), {}),
};
},
{},
)
);
const flattenedArray = array.map(o => flat(o));
Those solutions will work with any depth.
Answer from fxlemire on Stack OverflowYou can simply use the npm package flat.
import flat from 'flat';
const array = [
{
a: 'a',
b: {
bb: 'bb',
},
c: {
cc1: 'cc1',
cc: {
ccc: 'ccc',
ccd: 'ccd',
},
},
},
// ...
];
const flattenedArray = array.map(flat);
/*
flattenedArray === [
{
a: 'a',
b.bb: 'bb',
c.cc1: 'cc1',
c.cc.ccc: 'ccc',
c.cc.ccd: 'ccd',
},
// ...
]
*/
And if you want to implement it yourself, here's my implementation of flat:
const flat = (obj, concatenator = '.') => (
Object.keys(obj).reduce(
(acc, key) => {
if (typeof obj[key] !== 'object' || !obj[key]) {
return {
...acc,
[key]: obj[key],
};
}
const flattenedChild = flat(obj[key], concatenator);
return {
...acc,
...Object.keys(flattenedChild).reduce((childAcc, childKey) => ({ ...childAcc, [`
{concatenator}${childKey}`]: flattenedChild[childKey] }), {}),
};
},
{},
)
);
const flattenedArray = array.map(o => flat(o));
Those solutions will work with any depth.
You can do this without lodash (or another library) by iterating over the keys of each item in the original array, checking their type, and further iterating over their internal keys, building new keys to hold the right values.
const array = [{
id: 123,
name: 'John',
summary1: {
count: 3,
sum: 10
},
summary2: {
count: 10,
sum: 20
}
}];
let newArray = array.map(item => {
let newObj = {};
Object.keys(item).forEach(key => {
if (typeof item[key] === 'object') {
Object.keys(item[key]).forEach(innerKey => {
newObj[`${key}_${innerKey}`] = item[key][innerKey];
});
} else {
newObj[key] = item[key];
}
});
return newObj;
});
console.log(newArray);
Granted, this isn't necessarily very pretty or flexible (following your assumption of a single level deep).
One of the easiest solutions would be, merging the nested object with parent,
_.merge(data, data.dates);
This will bring all data.dates property into data. Then delete data.dates
delete data.dates
ES6 version:
var data = {
"dates": {
"expiry_date": "30 sep 2018",
"available": "30 sep 2017",
"min_contract_period": [{
"id": 1,
"name": "1 month",
"value": false
}, {
"id": 2,
"name": "2 months",
"value": true
}, {
"id": 3,
"name": "3 months",
"value": false
}]
},
"price": {
"curreny": "RM",
"min": 1500,
"max": 2000
}
};
var {dates: {expiry_date, ...dates}, ...rest} = data;
var flatData = {dates, expiry_date, ...rest}
console.log(flatData)
One thing to note is that you have to be careful with deeply nested destructuting. In this example if data.dates is undefined and you'll try to destructure it, error will be thrown.
You can create a recursive function (getSchema) that checks if a value (val) is an object (arrays included), iterate it with _.flatMap(), and collects the keys until it hits a value which is not an object. It then joins the collected keys and returns the string.
const getSchema = (val, keys = []) =>
_.isObject(val) ? // if it's an object or array
_.flatMap(val, (v, k) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Without lodash, the main change is to use Object.entries() to get an array of [key, value] pairs, since Array.flatMap() can't iterate objects:
const getSchema = (val, keys = []) =>
typeof val === 'object' && val !== null ? // if it's an object or array
Object.entries(val) // get [key, value] pairs of object/array
.flatMap(([k, v]) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
inspired by the answer given in this post and understanding you just want to get the property-names, not values, you could do it like this. sorry, this uses plain javascript.
function flattenObjectToKeyArray(ob) {
var toReturn = [];
for (var prop in ob) {
if (!ob.hasOwnProperty(prop)) continue;
if ((typeof ob[prop]) == 'object' && ob[prop] !== null) {
var flatObject = flattenObjectToKeyArray(ob[prop]);
for (var idx = 0; idx < flatObject.length; idx++) {
toReturn.push(prop + '.' + flatObject[idx]);
}
} else {
toReturn.push(prop);
}
}
return toReturn;
}
» npm install @silvered/flatten-object-keys
I wanted to flatten my deep object to one level depth. None of the above solutions worked for me.
My input:
{
"user": {
"key_value_map": {
"CreatedDate": "123424",
"Department": {
"Name": "XYZ"
}
}
}
}
Expected output:
{
"user.key_value_map.CreatedDate": "123424",
"user.key_value_map.Department.Name": "XYZ"
}
Code that worked for me:
function flattenObject(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object' && ob[i] !== null) {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
}
Flattening Object can be done using recursion as below :
Sample Input
const obj = {
name: "test",
address: {
personal: "abc",
office: {
building: 'random',
street: 'some street'
}
}
}
Expected Output
{
name : "test",
address_personal: "abc"
address_office_building: "random"
address_office_street: "some street"
}
My Solution
function flattenObj(obj, parent, res = {}){
for(let key in obj){
let propName = parent ? parent + '_' + key : key;
if(typeof obj[key] == 'object'){
flattenObj(obj[key], propName, res);
} else {
res[propName] = obj[key];
}
}
return res;
}
Hope it helps