4

I'm working with data returned from a 3rd party API and I really only need to retain certain properties from said objects. Each object is heavily nested with other objects contained within arrays, and occasionally a property that is just an array of strings. For instance, I get returned JSON such as:

{
  itemId: '12345',
  attributes: [ { attr1: ['red'], attr2: ['large', 'round'], attr3: ['obnoxious'] } ],
  habits: [ 'bounce', 'roll', 'deflate' ]
}

This is just an example, but the real data is pretty messy and I would like to flatten everything down to a single object with no nesting and do it in the most efficient manner. I have experimented with several 'manual' ways of doing so with loops, but I feel like there must be some more efficient and resource-conscientious manner. I've looked through ES6-included methods of working with objects, but I can't seem to get the combination right.

The real object I'm working with:

{ itemId: [ '263010774375' ],
  title: [ 'Star Wars Destiny Spirit of Rebellion - LEGENDARY' ],
  globalId: [ 'EBAY-US' ],
  primaryCategory: [ { categoryId: [Array], categoryName: [Array] } ],
  galleryURL: [ 
  'http://thumbs4.ebaystatic.com/pict/263010774375404000000004_1.jpg' ],
  viewItemURL: [ 'http://www.ebay.com/itm/Star-Wars-Destiny-Spirit-Rebellion-
  LEGENDARY-/263010774375?var=562018071609' ],
  paymentMethod: [ 'PayPal' ],
  autoPay: [ 'false' ],
  postalCode: [ '78124' ],
  location: [ 'Marion,TX,USA' ],
  country: [ 'US' ],
  shippingInfo: 
   [ { shippingServiceCost: [Array],
       shippingType: [Array],
       shipToLocations: [Array],
       expeditedShipping: [Array],
       oneDayShippingAvailable: [Array],
       handlingTime: [Array] } ],
  sellingStatus: 
   [ { currentPrice: [Array],
       convertedCurrentPrice: [Array],
       sellingState: [Array] } ],
  listingInfo: 
   [ { bestOfferEnabled: [Array],
       buyItNowAvailable: [Array],
       startTime: [Array],
       endTime: [Array],
       listingType: [Array],
       gift: [Array],
       watchCount: [Array] } ],
  returnsAccepted: [ 'true' ],
  condition: [ { conditionId: [Array], conditionDisplayName: [Array] } ],
  isMultiVariationListing: [ 'true' ],
  topRatedListing: [ 'false' ] }`

The output I'd like to get would include bringing properties that are nested in arrays nested in other object properties that are also nested in arrays. My final object would only have one level, for example:

{
  itemID: '12345',
  title: 'something',
  currentPrice: 20.00,
  endTime: '2017-07-01',
  condition: conditionDisplayName[0], // ex. 'Used'
  location: 'Springfield, USA'
}
Smitty
  • 1,765
  • 15
  • 22
  • should your output be `{itemId: '12345', attr1: ['red'], attr2: ['large', 'round'], attr3: ['obnoxious'], habits: [ 'bounce', 'roll', 'deflate' ]}`? – TheChetan Sep 01 '17 at 04:20
  • That would be preferable, but at the most minimal level. This is just an example as the actual object I am looking at I've added in an edit to my question. – Smitty Sep 01 '17 at 04:23
  • Can also display the output? That will help you get a better answer. – TheChetan Sep 01 '17 at 04:30
  • @TheChetan as to what I’d like to end up with? Thanks – Smitty Sep 01 '17 at 04:31
  • Unless you show your desired output given some input it's not really possible to answer. – Evan Trimboli Sep 01 '17 at 04:31
  • Understood, have edited question to reflect desired output. Getting the output I want seems trivial, but I'm more concerned about efficiency as some of the data returned can be rather large. Paginated results of 100 objects per page at a max of 200 pages or so. – Smitty Sep 01 '17 at 04:36
  • Why do you want to flatten at all? The hierarchy looks quite useful to me. Maybe you should think the other way and change the "thing" that receives these data in such a way that it can cope with the nested structure? – Rob Sep 01 '17 at 04:38
  • @Robert that thought had crossed my mind - I'm not sure where to begin in that regards. – Smitty Sep 01 '17 at 04:40
  • Well, you could describe what actually *happens* with the data. You probably need to read out certain properties out of it. Accessing these properties is as simple as reading from a flattened key/value structure. – Rob Sep 01 '17 at 04:43
  • I think that may be what I started doing (new to JS), but it seemed cumbersome to have to access what I needed in this manner: `item.data.findCompletedItemsResponse[0].searchResult[0].item.listingInfo[0].endTime[0]` – Smitty Sep 01 '17 at 04:46

1 Answers1

1

Check this answer.

Try something like this using recursion:

var obj = {
    prop: 1,
    arr: [
        { id: 1, name: "larry" },    
        { id: 2, name: "curly" },
        { id: 3, name: "moe" }
    ],
    complex: {
        place: {
            greeting: "hello world"   
        }
    }
};

function flatten(obj){
 var root = {};
 (function tree(obj, index){
   var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
   for(var key in obj){
    if(!obj.hasOwnProperty(key))continue;
    root[index+key+suffix] = obj[key];
    if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
    if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");   
   }
 })(obj,"");
 return root;
}
   
var flat = flatten(obj);
console.log(flat);
Pritam Banerjee
  • 17,953
  • 10
  • 93
  • 108