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 Overflow
Top answer
1 of 4
13

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.

2 of 4
4

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).

🌐
Lodash
lodash.com › docs
Lodash Documentation
This method is like _.flatMap except that it recursively flattens the mapped results up to depth times. ... Iterates over elements of collection and invokes iteratee for each element. The iteratee is invoked with three arguments: (value, index|key, collection). Iteratee functions may exit iteration early by explicitly returning false. Note: As with other "Collections" methods, objects with a "length" property are iterated like arrays.
🌐
GitHub
github.com › lodash › lodash › issues › 2240
Flatten object to paths [feature request] · Issue #2240 · lodash/lodash
April 12, 2016 - Something I've made a couple times to solve certain nested object problems. Flattening an object into path keys: { my: { nested: { object: 'leaf' } } } // to { 'my.nested.object&#39...
Author   c-dante
🌐
GeeksforGeeks
geeksforgeeks.org › javascript › lodash-_-flatten-method
Lodash _.flatten() Method - GeeksforGeeks
September 2, 2024 - // Requiring the lodash library const _ = require("lodash"); // Original array let array1 = [[{ "a": 1 }], [{ "b": 2 }, { "c": 3 }]] // Using _.flatten() method let newArray = _.flatten(array1); // Printing original Array console.log("original ...
🌐
Tabnine
tabnine.com › home page › code › javascript › lodash
lodash.flatten JavaScript and Node.js code examples | Tabnine
/** * Prints the plan */ print() { if (this.isEmpty()) { this.options.logger.info( chalk.yellowBright('No mutations to be performed')); return; } this.options.logger.info(); this.options.logger.info('Index sync plan:'); this.options.logger.info(); flatten(this.mutations).forEach((mutation) => { mutation.print(this.options.logger); // Add blank line this.options.logger.info(); }); } ... static async getList(artInfoList) { const artInfoObj = { 100: [], 200: [], 300: [], } for (let artInfo of artInfoList) { artInfoObj[artInfo.type].push(artInfo.art_id) } const arts = [] for (let key in artInfoObj) { const ids = artInfoObj[key] if (ids.length === 0) { continue } key = parseInt(key) arts.push(await Art._getListByType(ids, key)) } return flatten(arts) }
Top answer
1 of 3
3

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)

2 of 3
1

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
npmjs.com › package › @silvered › flatten-object-keys
@silvered/flatten-object-keys - npm
March 10, 2022 - import { flattenObjectKeys } from "@silvered-nyc/flatten-object-keys"; import _ from "lodash"; const object = { firstName: "robert", age: 28, social: { header: "Good mindsets help", posts: { recent: ["Good things on the way"], }, }, views: { life: [ "The best is yet to be", "Do good and good will come to you.", "You can't go through life allowing pain to dictate how you behave", "Pain is inevitable, suffering is optional", ], }, }; const keys = flattenObjectKeys(object); const bagOfWords = keys.reduce( (pv: { [key: string]: { count: number; sources: string[] } }, key) => { // lodash to get nes
      » npm install @silvered/flatten-object-keys
    
Published   Mar 10, 2022
Version   1.0.5
Author   Silvered
🌐
JSFiddle
jsfiddle.net › asicfr › v2scrLgw
Lodash flatten object - JSFiddle - Code Playground
For now it's a BYOK implmentation which means you need to provide your own API Key − you can get it for free.
Find elsewhere
🌐
GitHub
github.com › lodash › lodash › issues › 1228
Is there a functionality to flatten/deflatten an object? · Issue #1228 · lodash/lodash
May 25, 2015 - Hi there, I have the following object/array of objects: Object1: { id: 2, balance: 130, 'Issue : { 'id': 1, 'currency': 'EUR' } }``` Object2: ```json { id: 2, balance: 130, 'Issue.id': 1, 'Issue.currency': 'EUR' } Is there a way to 'defl...
Published   May 25, 2015
Author   moatazelmasry2
🌐
TecHighness
techighness.com › home › java script flatten deeply nested array of objects into single level array
JavaScript Flatten Deeply Nested Array of Objects Into Single Level Array - TecHighness
December 26, 2022 - We can also _.find to get the member object: const _ = require("lodash"); const familyTree = [ // ... ]; const flatArray = _.flatMapDeep(familyTree, getMembers); // ... console.log(_.some(flatArray, ({ age }) => age <= 2)); // => true console.log(_.find(flatArray, ({ age }) => age <= 2)); // => { id: '0e11874f', name: 'Ian', age: 2 } ... Python Check if Key Exists in Deeply Nested Dictionary or List of Dictionaries, Without Knowing the Path
🌐
30 Seconds of Code
30secondsofcode.org › home › javascript › object › flatten or unflatten object
Flatten or unflatten a JavaScript object - 30 seconds of code
January 3, 2024 - Otherwise, we add the appropriate prefixed key-value pair to the accumulator object. In the previous example, we used a delimiter of . to separate the keys, but this can be customized, using an additional argument. Finally, the last argument is used for the recursive calls and should always be omitted unless you want every key to have a prefix. const flattenObject = (obj, delimiter = '.', prefix = '') => Object.keys(obj).reduce((acc, k) => { const pre = prefix.length ?
🌐
Jimtotheb
jimtotheb.github.io › lodash-fun › index.html
lodash-fun | lodash-fun
August 12, 2018 - The object to flatten. flowP<T>(...funs: ((val: any) => any)[]): (initial: T) => Promise<any> ... Creates a function that resolves the result of applying the given functions from left to right. let FromRightToLeft = flowP( s => `${s} Left`, s => `${s} to` , s => `${s} Right` ) await FromLeftToRight('From') // From Left to Right ... Accepts a ConformError instance and formats its validationErrors into human readable form. ... With(keys: string[], constraintFun?: (item: any) => boolean, obj?: any): (CurriedFunction3<any, any, any, boolean> & CurriedFunction2<any, any, boolean> & CurriedFunction1<any, boolean> & false) | (CurriedFunction3<any, any, any, boolean> & CurriedFunction2<any, any, boolean> & CurriedFunction1<any, boolean> & true)
🌐
npm
npmjs.com › search
flatten object - npm search
Safely flatten a nested JavaScript object. ... jessie-codes• 2.1.0 • 2 years ago • 35 dependents • MITpublished version 2.1.0, 2 years ago35 dependents licensed under $MIT ... GitHub Actions• 7.3.4 • 2 months ago • 39 dependents • MITpublished version 7.3.4, 2 months ago39 dependents licensed under $MIT ... The lodash method `_.flatten` exported as a module.
Top answer
1 of 1
43

The approach below uses flatMap to flatten tags acquired through map. Finally, use the spread operator to assign the values from tag and the feature's name.

const result = _.flatMap(features, ({ name, tags }) =>
  _.map(tags, tag => ({ name, ...tag }))
);

const features = [{
    'name': 'feature1',
    'tags': [{
      'weight': 10,
      'tagName': 't1'
    }, {
      'weight': 20,
      'tagName': 't2'
    }, {
      'weight': 30,
      'tagName': 't3'
    }]
  },
  {
    'name': 'feature2',
    'tags': [{
      'weight': 40,
      'tagName': 't1'
    }, {
      'weight': 5,
      'tagName': 't2'
    }, {
      'weight': 70,
      'tagName': 't3'
    }]
  },
  {
    'name': 'feature3',
    'tags': [{
      'weight': 50,
      'tagName': 't1'
    }, {
      'weight': 2,
      'tagName': 't2'
    }, {
      'weight': 80,
      'tagName': 't3'
    }]
  }
];

const result = _.flatMap(features, ({ name, tags }) =>
  _.map(tags, tag => ({ name, ...tag }))
);

console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Here's a plain javascript solution that uses Array#reduce and Array#map with the help of Array#concat to flatten the array.

const result = features.reduce(
  (result, { name, tags }) => result
    .concat(tags.map(tag => ({ name, ...tag }))), 
  []
);

const features = [{
    'name': 'feature1',
    'tags': [{
      'weight': 10,
      'tagName': 't1'
    }, {
      'weight': 20,
      'tagName': 't2'
    }, {
      'weight': 30,
      'tagName': 't3'
    }]
  },
  {
    'name': 'feature2',
    'tags': [{
      'weight': 40,
      'tagName': 't1'
    }, {
      'weight': 5,
      'tagName': 't2'
    }, {
      'weight': 70,
      'tagName': 't3'
    }]
  },
  {
    'name': 'feature3',
    'tags': [{
      'weight': 50,
      'tagName': 't1'
    }, {
      'weight': 2,
      'tagName': 't2'
    }, {
      'weight': 80,
      'tagName': 't3'
    }]
  }
];

const result = features.reduce(
  (result, { name, tags }) => result
    .concat(tags.map(tag => ({ name, ...tag }))), 
  []
);

console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

🌐
Educative
educative.io › answers › what-is-the-flattendeep-method-in-lodash
What is the _.flattenDeep() method in Lodash?
The _.flattenDeep() method in Lodash is used to recursively flatten an array, that is, to flatten all the nested arrays completely.
🌐
GitHub
github.com › lodash › lodash › pull › 5869 › files
feat: flatten an object functionality by david-pilny · Pull Request #5869 · lodash/lodash
flattenObject Function The ... with nested properties into a single-level object with dot-separated keys representing the path to each value in the original object....
Author   lodash
🌐
codestudy
codestudy.net › blog › flatten-nested-objects-with-lodash
How to Flatten Nested Objects with Lodash in JavaScript: A Step-by-Step Guide — codestudy.net
Lodash doesn’t have a built-in _.flattenObject function, but we can combine Lodash utilities to create a robust object-flattening tool. Let’s build a function to flatten nested objects into key-value pairs with dot-separated keys.