0

So i have this kind of array from json

data : [{
    article_categories : {
        id : "xxx",
        name : "xxx"
    },
    article : "xxx",
    publisher : "xxx"
}]

I wanted to create another multi dimension array for those array and i want to keep the fields name (the name "article","publisher" and so on in the array) with value in there but i have no idea to get fields name

And i also want to do some conditional if to only include some fields into my new array by checking from this array

thead: [
    { key: "article"},
    { key: "article_categories.name"},
    .....
]

so i the end there will be array like this

newArray: [
 {article:"xxx",publisher: "xxx",article_categories.name:"xxx"},
 {article:"xxx",publisher: "xxx",article_categories.name:"xxx"}
 ....
]

how to do that? i tried

thead.forEach(function(column){
  data.forEach(function(key,value){
      if(column.key == key){
         newArray[key] = value
      }
  })
})

but it just not working....

Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
PamanBeruang
  • 1,531
  • 5
  • 27
  • 64

3 Answers3

1

If you're open to use lodash, it will be so simple. Lodash is efficient in evaluating JSON expressions using .get() method, so you won't be bothered to evaluate the expression against objects.

.chain() adds icing on the cake, making the code simpler to read, yet performing many complex operations under the hood.

Try the following snippet:

var keys = [{
    key: "article"
  },
  {
    key: "article_categories.name"
  }
];

var data = [{
  article_categories: {
    id: "xxx",
    name: "xxx"
  },
  article: "xxx",
  publisher: "xxx"
}];

var result = _.chain(data)
  .map(function(item) {
    var object = {};

    keys.forEach(function(key) {
      object[key.key] = _.get(item, key.key);
    });

    return object;
  })
  .value();

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
31piy
  • 23,323
  • 6
  • 47
  • 67
  • 4
    That requires loading a 70kb (minified!) library just to iterate through an array... :/ – Jeremy Thille Sep 19 '17 at 11:39
  • well i already using lodash so i don;t mind it, but sorry i have another question but still related to this... what if my thead json array is an object and be like this thead: { article : "string", publisher: "string", ....} how do i modified those code? – PamanBeruang Sep 19 '17 at 12:25
  • @LaurensiusTony -- In that case, you will only be interested in the object's keys. So, you can replace `keys.forEach` with `_.keys(tdata).forEach( ... )`. – 31piy Sep 19 '17 at 13:10
  • tdata is what? and also i still don't quite understand your code, it so simple that is seems like a magic... – PamanBeruang Sep 19 '17 at 13:44
1

I think that first, you should simplify this :

thead = [
    { key: "article"},
    { key: "article_categories.name"},
    .....
]

as this :

thead = ["article", "article_categories.name"]

Here's my go at it :

const data = [{
  article_categories : {
   id : "xxx",
   name : "xxx"
  },
  article : "xxx",
  publisher : "xxx"
 }],
 thead = ["article", "article_categories.name"]

const newArray = data.map( obj => {
 let output = {}
 thead.forEach(key => {
  if(key.includes(".")){
   let subkeys = key.split(".")
   output[key] = obj[subkeys[0]][subkeys[1]]
  } else {
   output[key] = obj[key]
  }
 })
 return output
})

console.log(newArray)
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • What if `article_categories.name` is changed to something like `a.b[0].c`? Using lodash is a pain in terms of loading a library, but is better suited in this case because parsing JSON expression and evaluating it is something like reinventing the wheel, and is of-course prone to errors. – 31piy Sep 19 '17 at 11:42
  • If it's changed, then the code will need to be adjusted. In the meantime, OP said nothing about changing it, this answers the question and doesn't load a 70k library ;) – Jeremy Thille Sep 19 '17 at 11:44
  • Haha, that justifies it for now :) – 31piy Sep 19 '17 at 11:47
1

You can use a flatten function to flatten the object with dot notation.

Then map the flattened object to take an item each and filter only the keys that are allowed and reduce to reconstruct the object.

To answer your original question, you can use Object.keys() to get the keys of an Object

let data = [{
    article_categories : {
        id : "xxx",
        name : "xxx"
    },
    article : "xxx",
    publisher : "xxx"
},{
    article_categories : {
        id : "xxx2",
        name : "xxx2"
    },
    article : "xxx2",
    publisher : "xxx2"
}]

let thead = [
    { key: "article"},
    { key: "article_categories.name"},
];

let allowed_keys = thead.map(x=> x.key);

let flattened = data.map(item => flatten(item, '', ''));

// console.log(flattened);

let result = flattened.map(item => {
  return Object.keys(item)
    .filter(key => allowed_keys.includes(key))
    .reduce((obj, key) => {
      obj[key] = item[key];
      return obj;
    }, {})
});

console.log(result);


/**
 * Recursively flattens a JSON object using dot notation.
 *
 * NOTE: input must be an object as described by JSON spec. Arbitrary
 * JS objects (e.g. {a: () => 42}) may result in unexpected output.
 * MOREOVER, it removes keys with empty objects/arrays as value (see
 * examples bellow).
 *
 * @example
 * // returns {a:1, 'b.0.c': 2, 'b.0.d.e': 3, 'b.1': 4}
 * flatten({a: 1, b: [{c: 2, d: {e: 3}}, 4]})
 * // returns {a:1, 'b.0.c': 2, 'b.0.d.e.0': true, 'b.0.d.e.1': false, 'b.0.d.e.2.f': 1}
 * flatten({a: 1, b: [{c: 2, d: {e: [true, false, {f: 1}]}}]})
 * // return {a: 1}
 * flatten({a: 1, b: [], c: {}})
 *
 * @param obj item to be flattened
 * @param {Array.string} [prefix=[]] chain of prefix joined with a dot and prepended to key
 * @param {Object} [current={}] result of flatten during the recursion
 *
 * @see https://docs.mongodb.com/manual/core/document/#dot-notation
 */
function flatten (obj, prefix, current) {
  prefix = prefix || []
  current = current || {}
  if (typeof (obj) === 'object' && obj !== null) {
    Object.keys(obj).forEach(key => {
      flatten(obj[key], prefix.concat(key), current)
    })
  } else {
    current[prefix.join('.')] = obj
  }
  return current
}
sabithpocker
  • 15,274
  • 1
  • 42
  • 75