1

I am pretty new to JavaScript, and am working with Node.JS to access an API and store the response in a SQL Server. I am using the "request" and "mssql" Node packages. I am not attached to these, they just seemed to be what I needed and have good documentation and support.

My question: I have the JSON response from the API in the following format:

requests = [ { 
  url: 'https://domain.zendesk.com/api/v2/requests/2.json',
  id: 2,
  status: 'closed',
  priority: 'normal',
  type: 'incident',
  subject: 'Test Ticket',
  description: 'Test ticket',
  organization_id: 10101010101,
  via: { 
    channel: 'email',
    source: { 
      from: { 
        address: 'bill.bob@domain.com',
        name: 'Bill Bob' 
      },
      to: { 
        name: 'Company Helpdesk',
        address: 'testzendesk@domain.com' 
      },
      rel: null 
    },
  },
  custom_fields:[ 
    { id: 31368658, value: null },
    { id: 29221487, value: null },
    { id: 31636418, value: null },
    { id: 29498078, value: null },
    { id: 31659217, value: null } 
  ],
  requester_id: 2020202020,
  collaborator_ids: [],
  is_public: true,
  due_at: null,
  can_be_solved_by_me: false,
  created_at: '2015-03-05T05:55:22Z',
  updated_at: '2015-03-12T05:01:51Z',
  recipient: 'testzendesk@domain.com',
  followup_source_id: null,
  assignee_id: 30303030303,
  ticket_form_id: null,
  fields: [ 
    { id: 31368658, value: null },
    { id: 29221487, value: null },
    { id: 31636418, value: null },
    { id: 29498078, value: null },
    { id: 31659217, value: null } 
  ] 
},
{ 
  url: 'https://domain.zendesk.com/api/v2/requests/2.json',
  id: 3,
  status: 'closed',
  priority: 'normal',
  type: 'incident',
  subject: 'Test Ticket',
  description: 'Test ticket',
  organization_id: 10101010101,
  via: { 
    channel: 'email',
    source: { 
      from: { 
        address: 'bill.bob@domain.com',
        name: 'Bill Bob' 
      },
      to: { 
        name: 'Company Helpdesk',
        address: 'testzendesk@domain.com' 
      },
      rel: null 
    }
  },
  custom_fields: [ 
    { id: 31368658, value: null },
    { id: 29221487, value: null },
    { id: 31636418, value: null },
    { id: 29498078, value: null },
    { id: 31659217, value: null } 
  ],
  requester_id: 2020202020,
  collaborator_ids: [],
  is_public: true,
  due_at: null,
  can_be_solved_by_me: false,
  created_at: '2015-03-05T05:55:22Z',
  updated_at: '2015-03-12T05:01:51Z',
  recipient: 'testzendesk@domain.com',
  followup_source_id: null,
  assignee_id: 30303030303,
  ticket_form_id: null,
  fields: [ 
    { id: 31368658, value: null },
    { id: 29221487, value: null },
    { id: 31636418, value: null },
    { id: 29498078, value: null },
    { id: 31659217, value: null } 
  ] 
} ];

I need to pull the children objects out, i.e. the "via", "custom_fields" and "fields" with the parent IDs. So for the first object, each of the "via" children objects would also have the ID of 2, and would have "channel", "source", and "ID" elements.

Something like this:

parents:

[   
    { 
        url: 'https://domain.zendesk.com/api/v2/requests/2.json',
        id: 2,
        status: 'closed',
        priority: 'normal',
        type: 'incident',
        subject: 'Test Ticket',
        description: 'Test ticket',
        organization_id: 10101010101,
        requester_id: 2020202020,
        collaborator_ids: [],
        is_public: true,
        due_at: null,
        can_be_solved_by_me: false,
        created_at: '2015-03-05T05:55:22Z',
        updated_at: '2015-03-12T05:01:51Z',
        recipient: 'testzendesk@domain.com',
        followup_source_id: null,
        assignee_id: 30303030303,
        ticket_form_id: null
    },
    { url: 'https://domain.zendesk.com/api/v2/requests/2.json',
        id: 3,
        status: 'closed',
        priority: 'normal',
        type: 'incident',
        subject: 'Test Ticket',
        description: 'Test ticket',
        organization_id: 10101010101,
        requester_id: 2020202020,
        collaborator_ids: [],
        is_public: true,
        due_at: null,
        can_be_solved_by_me: false,
        created_at: '2015-03-05T05:55:22Z',
        updated_at: '2015-03-12T05:01:51Z',
        recipient: 'testzendesk@domain.com',
        followup_source_id: null,
        assignee_id: 30303030303,
        ticket_form_id: null 
    }
]

via:

[
    { 
        channel: 'email',
        parent_id: 2
    },
    {
        channel: 'email',
        parent_id: 3
    }
]

via_source_from:

[
    {
        address: 'bill.bob@domain.com',
        name: 'Bill Bob',
        parent_id: 2
    },
    {
        address: 'bill.bob@domain.com',
        name: 'Bill Bob',
        parent_id: 2
    }
]

via_source_to:

[
    {
        name: 'Company Helpdesk',
        address: 'testzendesk@domain.com',
        parent_id: 2
    },
    {
        name: 'Company Helpdesk',
        address: 'testzendesk@domain.com',
        parent_id: 2
    }
]

custom_fields:

[
    { parent_id: 2, id: 31368658, value: null },
    { parent_id: 2, id: 29221487, value: null },
    { parent_id: 2, id: 31636418, value: null },
    { parent_id: 2, id: 29498078, value: null },
    { parent_id: 2, id: 31659217, value: null },
    { parent_id: 3, id: 31368658, value: null },
    { parent_id: 3, id: 29221487, value: null },
    { parent_id: 3, id: 31636418, value: null },
    { parent_id: 3, id: 29498078, value: null },
    { parent_id: 3, id: 31659217, value: null } 
]

fields:

[
    { parent_id: 2, id: 31368658, value: null },
    { parent_id: 2, id: 29221487, value: null },
    { parent_id: 2, id: 31636418, value: null },
    { parent_id: 2, id: 29498078, value: null },
    { parent_id: 2, id: 31659217, value: null },
    { parent_id: 3, id: 31368658, value: null },
    { parent_id: 3, id: 29221487, value: null },
    { parent_id: 3, id: 31636418, value: null },
    { parent_id: 3, id: 29498078, value: null },
    { parent_id: 3, id: 31659217, value: null }
]

I have searched around, and have not found anything that would allow me to do this.

Thanks a bunch!

Raghav Garg
  • 3,059
  • 2
  • 18
  • 29
David
  • 65
  • 11
  • What have you tried to code so far? Also, this seems like one big object, how do you know that the order is always correct and the fields that you want to pull out are always associated with the ID above them? See here: https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order – tima Aug 22 '17 at 16:24
  • @tima good call. This would be an array of objects, not one big object. I have updated the question to reflect this. – David Aug 22 '17 at 16:36

1 Answers1

1

You can do something like this, there isn't much to describe but still if couldn't understand anything in below code, please comment.

I haven't manipulated the parents object, but you can delete the desired fields yourself. you can refer to this link. But remember to manipulate after cloning the object because delete operator mutate the original object.

let
parents = [],
via = [],
via_source_from = [],
via_source_to = [],
custom_fields = [],
fields = [];

requests.forEach( record => {

  let pid = record.id;

  parents = [ ...parents, record ];

  via = [ ...via, Object.assign({}, { parent_id: pid, channel: record.via.channel } ) ];

  via_source_from = [ ...via_source_from, Object.assign({}, { parent_id: pid }, record.via.source.from ) ]

  via_source_to = [ ...via_source_to, Object.assign({}, { parent_id: pid }, record.via.source.to ) ]

  custom_fields = [ ...custom_fields, ...record.custom_fields.map( f => { return Object.assign({}, f, { parent_id: pid }) } ) ]

  fields = [ ...fields, ...record.fields.map( f => { return Object.assign({}, f, { parent_id: pid }) } ) ]

});


console.log("parent: ", parent);
console.log("via: ", via);
console.log("via_source_from: ", via_source_from);
console.log("via_source_to: ", via_source_to);
console.log("custom_fields: ", custom_fields);
console.log("fields: ", fields);

Update

I have just created an empty array in start to add the specific data on each iteration of requests. Then concatenate the array with relevant data using mainly four concepts, given below.

Spread Operator

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2]; // returns new array [0, 1, 2, 3, 4, 5]
var arr4 = [...arr3, 6]; // returns new array [0, 1, 2, 3, 4, 5, 6]

This is new spread operator of javascript. You can refer this link for better understanding. In case of array, it works same as array.concat just more clean syntax.

Object assign

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

var obj = { a: 1 };
var copy = Object.assign({}, obj, { b: 2 }); // we can add as many object as we need.
copy.c = 3;
console.log(obj); // { a: 1 }
console.log(copy); // { a: 1, b: 2, c: 3 }

A great way to clone the object without having a reference to the original object. In short, to create immutable object. You can refer this link for better understanding.

Array.prototype.map()

The map() method creates a new array with the results of calling a provided function on every element in the calling array.

var numbers = [1, 5, 10, 15];
var doubles = numbers.map(function(x) {
    return x * 2;
});
// doubles is now [2, 10, 20, 30]
// numbers is still [1, 5, 10, 15]

Remember, it returns a new array and doesn't affect the original array. You have to return something from internal function else, you will have undefined at that index in final array. You can refer this link for better understanding.

Arrow Function

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target.

[ 'hi', 'ola', 'hello' ].map( greet => greet.length );
// returns [ 2, 3, 5 ]

Just a shorter syntax for writing a function. One main point is it doesn't bind its own this unlike function keyword, it really helps in defining scope of the this. You can refer this link for better understanding.

Raghav Garg
  • 3,059
  • 2
  • 18
  • 29
  • Boom! You're the man! Could you explain what you've done inside of the forEach? Really everything after the "=" signs inside of the forEach is new to me. Thanks! – David Aug 22 '17 at 18:47
  • @David, Updated the answer, please take a look and consider upvoting it also. – Raghav Garg Aug 22 '17 at 19:22
  • Thanks! I really appreciate the explanation! Being new to JS, every bit helps! – David Aug 23 '17 at 14:38
  • Is there a dynamic way to do this? I'd like to be able to pass any JSON into this function and have it find the children objects and build an array for each of them with the same name as the child object. Let me know if clarification is needed. Thanks! – David Sep 05 '17 at 17:49
  • @David, It can be done, but you don't have any defined format in your case. This is the best format I could make of your data. https://gist.github.com/raghavgarg1257/80c229144f767fef53d4b5a80a6712cc – Raghav Garg Sep 07 '17 at 03:53
  • thanks again for your most excellent help! I have been playing around with your code trying to make it even more dynamic. I need the "filers" to be dynamic as well as I need this to work for any set of data, not just the sample that I provided. [This is what I have come up with](https://gist.github.com/kadivadavidak/b19e3dc888ba7d0549f8f7d6361b10e1). Any ideas on how to make this better/completely dynamic? If I pass in an object that has further nested objects than the test, I don't want to have to account for every possible level (impossible). Thanks again!! – David Sep 13 '17 at 21:21