I have an Array nested withing an Object that's inside an Object which is also in an Object.
EDIT: My original data structure was malformed, so here is a screen cap of console.log(data):
This is being returned from an AJAX request and I'm having issue with getting to the array. The trick is that it will not always return 3 arrays per parent object, the amount of arrays is dependent on "length", or rather, "length" is a reflection of how many arrays to expect in each object that contains arrays. "OID" is the name of each array for both the "th" and "uh" objects.
There also happen to be several main objects, which are iterated with for(var i in data)
I've tried something like:
for(var i in data) {
for(var x in data[i].clicks) {
//And now I'm lost here
//I've tried getting the name of the Array from "OID"
//and going from there, that failed miserably.
}
}
How can I get at the contents of each of those arrays, it would be best if this can be done without knowing the name, quantity or length of said arrays.
Thanks in advance.
Your question and data structure is not very clear and I'm not familiar with the syntax you've used to declare your arrays, it seems incorrect to me.
If you intended your data structure be
data={
"Clicks": {
"length": 3, //Can be between 0-3
"OID": {
1: "1",
2: "2",
3: "3"
},
"th": {
1: [
null,
null,
null,
null
],
2: [
null,
null,
null,
null
],
3: [
null,
null,
null,
null
]
},
"uh": {
1: [
null,
null,
null,
null
],
2: [
null,
null,
null,
null
],
3: [
null,
null,
null,
null
]
}
}
};
and what you want to do is to iterate over all the elements in th and uh where the key comes from the entries in OID, you should be doing something like
for(var i = 1; i <= data.Clicks.length; i++){
data.Clicks.th[data.Clicks.OID[i]];
data.Clicks.uh[data.Clicks.OID[i]];
}
However, if your keys are not going to be anything but numbers, it seems like you might be better served by returning an array of arrays for each of th and uh:
data={
"Clicks": {
"th": [
[
null,
null,
null,
null
],
[
null,
null,
null,
null
],
[
null,
null,
null,
null
]
],
"uh": [
[
null,
null,
null,
null
],
[
null,
null,
null,
null
],
[
null,
null,
null,
null
]
]
}
};
and access it as
//assuming th and uh are of the same length always
for(var i = 1; i <= data.Clicks.th.length; i++){
data.Clicks.th[i];
data.Clicks.uh[i];
}
Related
I'm attempting to search each of the objects listed below from my dataset to see if they contain a value and if they do have that value to add the entire object into a new array.
Example:
Search List of Objects for Data "Continuous", if that data exists (Which it does in Doormerica and Hager) then take the entire object "Doormerica" and "Hager" and put the entire thing into a new array.
{
"Doormerica": {
"Floor Stops": [],
"Overhead Stop": [],
"Pull": [],
"Chain Stop": [],
"Continuous": [
"ALX",
"AL",
"QR"
],
"Kick": [],
"Back to Back Pull": [],
"Concealed": [],
"Butt": [],
"Surface Mount": [],
"Mop": [],
"Armor": [],
"Push": [],
"Wall Stops": []
},
"Schlage": {
"Mortise": [],
"Cylindrical": [
"ALX",
"AL",
"QR"
],
"Deadbolt": [],
"Dummy": [],
"Interconnected": [],
"Cylinders": []
},
"Pemko": {
"Sweeps": [
"345AV"
],
"Permiter Seal": [
"303AS"
],
"Thresholds": [
"170A"
],
"Rain Drip": [
"346C"
],
"Astragal": []
},
"LCN": {
"Surface Mount": [
"4040XP"
],
"Concealed": []
},
"Hager": {
"Butt": [],
"Continuous": []
}
}
Data Transformation
I decided to post this solution because the question asks how to "take the entire object". And including the name (Doormerica, Hager, etc.) in the result, either as a key or a value, seems an important part of the transformation. And we can accomplish this in one pass using Object.entries(), Array.reduce(), Spread Syntax, and the appropriate transformation code.
Examples of both transformations
[{"Doormerica": { "Floor Stops": [], ...}] // name as a key
[{ "Name": "Doormerica", "Floor Stops": [], ...}] // name as a value
Snippet
The snippet shows the complete code for doing both transformations.
const data = {Doormerica:{"Floor Stops":[],"Overhead Stop":[],Pull:[],"Chain Stop":[],Continuous:["ALX","AL","QR"],Kick:[],"Back to Back Pull":[],Concealed:[],Butt:[],"Surface Mount":[],Mop:[],Armor:[],Push:[],"Wall Stops":[]},Schlage:{Mortise:[],Cylindrical:["ALX","AL","QR"],Deadbolt:[],Dummy:[],Interconnected:[],Cylinders:[]},Pemko:{Sweeps:["345AV"],"Permiter Seal":["303AS"],Thresholds:["170A"],"Rain Drip":["346C"],Astragal:[]},LCN:{"Surface Mount":["4040XP"],Concealed:[]},Hager:{Butt:[],Continuous:[]}};
let subset = Object.entries(data).reduce((a,v) =>
v[1].hasOwnProperty("Continuous") ? [...a, {[v[0]]: v[1]} ] : a
// alternative methods adds a name property
// v[1].hasOwnProperty("Continuous") ? [...a, {Name: v[0], ...v[1]} ] : a
, []);
console.log(subset);
So we loop over the values of the object, search for our "term" on each of those values = objects. To search object for property you only need to check if obj[property] exists.
var obj = {Doormerica:{"Floor Stops":[],"Overhead Stop":[],Pull:[],"Chain Stop":[],Continuous:["ALX","AL","QR"],Kick:[],"Back to Back Pull":[],Concealed:[],Butt:[],"Surface Mount":[],Mop:[],Armor:[],Push:[],"Wall Stops":[]},Schlage:{Mortise:[],Cylindrical:["ALX","AL","QR"],Deadbolt:[],Dummy:[],Interconnected:[],Cylinders:[]},Pemko:{Sweeps:["345AV"],"Permiter Seal":["303AS"],Thresholds:["170A"],"Rain Drip":["346C"],Astragal:[]},LCN:{"Surface Mount":["4040XP"],Concealed:[]},Hager:{Butt:[],Continuous:[]}};
function my_search(obj, term) {
return Object.values(obj).reduce(function(agg, value) {
if (value[term]) {
agg.push(value)
}
return agg;
}, [])
}
console.log(my_search(obj, "Continuous"))
.as-console-wrapper {max-height: 100% !important}
I am trying to use Tabulator to create a list of tickets, The data is imported via AJAX url from the ticket system as a JSON as below.
{
"results": [
{
"cc_emails": [
"ram#freshdesk.com",
"diana#freshdesk.com"
],
"fwd_emails": [],
"reply_cc_emails": [
"ram#freshdesk.com",
"diana#freshdesk.com"
],
"ticket_cc_emails": [
"ram#freshdesk.com",
"diana#freshdesk.com"
],
"fr_escalated": false,
"spam": false,
"email_config_id": null,
"group_id": 35000204315,
"priority": 1,
"requester_id": 35020281588,
"responder_id": 35004154466,
"source": 2,
"company_id": null,
"status": 2,
"subject": "Support Needed...",
"association_type": null,
"to_emails": null,
"product_id": null,
"id": 188261,
"type": null,
"due_by": "2019-09-17T15:12:07Z",
"fr_due_by": "2019-07-01T15:12:07Z",
"is_escalated": false,
"description": "<div>Details about the issue...</div>",
"description_text": "Details about the issue...",
"custom_fields": {
"cf_category": null,
"cf_firstname": null,
"cf_surname": null,
"cf_user_trainging": null,
"cf_email_address": null,
"cf_office_365": null,
"cf_start_date": null,
"cf_permission_level": null,
"cf_hardware_type": null,
"cf_additional_information_specsoftware_etc": null,
"cf_vpn_access_required": false,
"cf_securitydistribution_group_membership": null,
"cf_mapped_network_driveslogin_script": null,
"cf_printers": null,
"cf_phone_extension": null,
"cf_ddi": null,
"cf_phone_group_membership": null,
"cf_user_who_requires_the_equipment": null,
"cf_requirment_date": null,
"cf_correctclosureused": null,
"cf_location": "A1"
},
"created_at": "2019-06-24T15:11:47Z",
"updated_at": "2019-06-24T15:59:00Z",
"associated_tickets_count": null,
"tags": []
}
],
"total": 1
}
The problem is the "custom_fields" is a JSON Object inside the main JSON object, is there a way to flatten this data out and display this as all one row in Tabulator? Any help appreciated?
My current result in Tabulator is it returns [object Object] for the custom_fields column. I would like to be able to see each of custom_fields in the row.
Handling Nested Data
There is no need to flatten the object, Tabulator can handle nested data for columns, if you use dot notation in the field name:
var table = new Tabulator("#example-table", {
columns:[
{title:"Category", field:"custom_fields.cf_category"}, //link column to nested field
],
});
Full details about nested data handling can be found in the Columns Documentation
Column Grouping
If you wanted to you could also use column grouping to show that the fields are a subset of a another property, for example we could define the top level columns as usual and then add column group to hold the custom columns
var table = new Tabulator("#example-table", {
columns:[
{title:"Subject", field:"subject"}, //standard column
{title:"Priorty", field:"priority"}, //standard column
{title:"Custom", columns:[ //column group to hold columns in custom_fields property
{title:"Category", field:"custom_fields.cf_category"},
{title:"First Name", field:"custom_fields.cf_firstname"},
]},
],
});
Full details can be found in the Column Grouping Documentation
If you're using es6+, you could easily achieve this by using rest in object destructuring and object spread.
const input = {
"results": [
{
"custom_fields": {...},
...
}
],
"total": 1
}
const expanded = input.results.map(result => {
const { custom_fields, ...rest } = result;
return { ...rest, ...custom_fields };
})
Here is a slightly different solution relying on function generators to traverse the original object, giving the possibility to eventually detect some duplicated keys.
This example can, of course, be altered by adding further checks (like whether you want to traverse all objects inside the main object and so on).
The current example takes care of:
Traversing the original object by excluding primitives and arrays.
Providing a flattenObject method that accepts an object as an argument and a callback as an eventual second argument that will be raised when a duplicated key is met. In that case, the default behavior is to take the "next" nested value as the new one. If false is returned in the callback, the current value is kept. The callback will provide the key and the value of the new value.
So, in a nutshell, the "real" code to acquire the desired result is this one:
// Case usage:
// Map the existing values.
input.results = input.results.map(i => flattenObject(i, (duplicatedKeyValuePair) => {
return false; // <-- keep the existing value if a duplicate is matched.
}));
console.log(input.results)
Of course, it's slightly more complicated then just flattening the desired property, but I wanted to give a more elastic flavour to it.
const input = {
"results": [
{
"cc_emails": [
"ram#freshdesk.com",
"diana#freshdesk.com"
],
"fwd_emails": [],
"reply_cc_emails": [
"ram#freshdesk.com",
"diana#freshdesk.com"
],
"ticket_cc_emails": [
"ram#freshdesk.com",
"diana#freshdesk.com"
],
"fr_escalated": false,
"spam": false,
"email_config_id": null,
"group_id": 35000204315,
"priority": 1,
"requester_id": 35020281588,
"responder_id": 35004154466,
"source": 2,
"company_id": null,
"status": 2,
"subject": "Support Needed...",
"association_type": null,
"to_emails": null,
"product_id": null,
"id": 188261,
"type": null,
"due_by": "2019-09-17T15:12:07Z",
"fr_due_by": "2019-07-01T15:12:07Z",
"is_escalated": false,
"description": "<div>Details about the issue...</div>",
"description_text": "Details about the issue...",
"test_duplicated_key": "hello! I should keep this!",
"custom_fields": {
"cf_category": null,
"cf_firstname": null,
"cf_surname": null,
"cf_user_trainging": null,
"cf_email_address": null,
"cf_office_365": null,
"cf_start_date": null,
"cf_permission_level": null,
"cf_hardware_type": null,
"cf_additional_information_specsoftware_etc": null,
"cf_vpn_access_required": false,
"cf_securitydistribution_group_membership": null,
"cf_mapped_network_driveslogin_script": null,
"cf_printers": null,
"cf_phone_extension": null,
"cf_ddi": null,
"cf_phone_group_membership": null,
"cf_user_who_requires_the_equipment": null,
"cf_requirment_date": null,
"cf_correctclosureused": null,
"cf_location": "A1",
"test_duplicated_key": "You should not see that."
},
"created_at": "2019-06-24T15:11:47Z",
"updated_at": "2019-06-24T15:59:00Z",
"associated_tickets_count": null,
"tags": []
}
],
"total": 1
}
/**
Traverse every property of the desired object, by returning the currently key-value pair looped. If the value is an object, it keeps traversing.
*/
function* traverseObject(obj) {
for ([key, value] of Object.entries(obj)) {
if (value && typeof(value) === 'object' && !Array.isArray(value)) {
yield* traverseObject(obj[key]);
}
else yield {key: key, value: value};
}
}
/**
Flattens the object by traversing every object inside it.
*/
function flattenObject(obj, onDuplicatedKey) {
let res = {};
for (keyValuePair of traverseObject(obj)) {
let add = true;
if (res.hasOwnProperty(keyValuePair.key)) {
add = onDuplicatedKey ? onDuplicatedKey.call(onDuplicatedKey, keyValuePair) : true; // default behavior: override with nested propeties.
}
if (add) res[keyValuePair.key] = keyValuePair.value;
}
return res;
}
/*
Sample usage.
const flattened = flattenObject(input.results[0], (record) => {
console.log('detected key value pair duplicate. Key:', record.key, ' value: ', record.value);
// true will override the value, false will not override the value.
return false;
});
*/
//console.log(flattened);
// Case usage:
// Map the existing values.
input.results = input.results.map(i => flattenObject(i, (duplicatedKeyValuePair) => {
return false; // <-- keep the existing value if a duplicate is matched.
}));
console.log(input.results);
Please note that the above case is just an example, I didn't spend much time testing every single property type, hence it can (of course) be reviewed and code quality and performances can be improved. It was just an example to show a different approach relying on different operators and logics.
As a (final) side note, I Think you can handle that with tabulator in some way, though I'm not sure you can render multiple columns out of a single property, which leads me to believe that altering the original object is probably the desired solution.
I have control Owners json object so i am trying to get worker from it , How can i assign worker json object to $scope.controlOwnerObj.worker ?
ctrl.js
if ($state.is('app.editControl')) {
angular.forEach($scope.controlDTO.controlOwners,function(owner){
$scope.selectedOwners = owner
})
// $scope.selectedOwners = $scope.controlDTO.controlOwners[0].worker;
// $scope.controlDTO.controlOwners[0].worker.fullName;
console.log('EDIT CONTROL OWNERS DATA', $scope.selectedOwners);
}
json.js
"controlOwners": [{
"worker": {
"workerKey": -1093,
"sourceFeed": null,
"statusLookUpCode": null,
"externalId": null,
"createdUserText": null,
"createdTimestamp": null,
"modifiedUserText": null,
"modifiedTimestamp": null,
"stdId": "ZK84T1N",
"ccId": null,
"empClasId": null,
"deptId": null,
"fullName": "Rajasekaran, Shanmuga",
}
}],
Specify the array index you want:
$scope.controlOwnerObj.worker = $scope.controlOwners[0].worker;
Try to use like this
$scope.controlOwners[0].worker.fullName = 'Rajasekaran, Shanmuga';
I got problem parse JSON data in proper format. This is my JSON data. I just want to grab beneAcctNumber from the data:
{
"restFilteredInterRegisteredAccounts": {
"101010-BPD Bali-Permata ALTO": {
"beneficiaryNote": null,
"beneficiaryName": "Permata ALTO",
"accountCurrency": "IDR",
"paymentType": null,
"beneficiaryIdType": null,
"transferLimit": null,
"beneficiaryResident": null,
"accountLimit": 5.0E7,
"bankName": "BPD Bali",
"lastModTime": null,
"ibInterAcctRef": null,
"bankCode": "000129",
"beneficiaryEmail": null,
"ibInterAcctStrcol1": null,
"ibInterAcctStrcol2": null,
"userId": 1551,
"beneAcctNumber": "101010",
"beneficiaryId": null,
"mobileNumber": null
}
},
}
I got undefined value after retrieved it. My attempt for this one:
restFilteredInterRegisteredAccounts[0].beneAcctNumber
restFilteredInterRegisteredAccounts is not an array, so [0] is undefined...
something like this would do it (assuming jsonObject is holding the json data):
jsonObject["restFilteredInterRegisteredAccounts"]["101010-BPD Bali-Permata ALTO"]["beneAcctNumber"]
restFilteredInterRegisteredAccounts has objects inside and this is not an array so index can not be used to get value. "101010-BPD Bali-Permata ALTO" behaves as a property restFilteredInterRegisteredAccounts. i am not sure if "101010-BPD Bali-Permata ALTO" is valid property name. ideally this should not contain spaces in between. if this works then try
restFilteredInterRegisteredAccounts["101010-BPD Bali-Permata ALTO"].beneAcctNumber
var da = {
"restFilteredInterRegisteredAccounts": {
"101010-BPD Bali-Permata ALTO": {
"beneficiaryNote": null,
"beneficiaryName": "Permata ALTO",
"accountCurrency": "IDR",
"paymentType": null,
"beneficiaryIdType": null,
"transferLimit": null,
"beneficiaryResident": null,
"accountLimit": 5.0E7,
"bankName": "BPD Bali",
"lastModTime": null,
"ibInterAcctRef": null,
"bankCode": "000129",
"beneficiaryEmail": null,
"ibInterAcctStrcol1": null,
"ibInterAcctStrcol2": null,
"userId": 1551,
"beneAcctNumber": "101010",
"beneficiaryId": null,
"mobileNumber": null
}
}, "somethingelse" : "whatever"
};
To access property (here beneAcctNumber) we will use
da.restFilteredInterRegisteredAccounts['101010-BPD Bali-Permata ALTO'].beneAcctNumber
Working Demo
I already found the correct answer. 100% working.
var output = "";
$.each(restFilteredInterRegisteredAccounts, function(index, item) {
output += item.beneAcctNumber ;
});
i got this structure:
{
"parent": {
"child-parent-1": {
"att1": null,
"att2": null,
},
"child-parent-2": {
"att1": null,
"att2": null,
}
}}
What i need to get, is the "child-parent-1" and "child-parent-2" names without knowing their names... since they are dynamically generated, like a hash code (askdl1km2lkaskjdnzkj2138).
Tried iterating but i couldn't make it work. I always get the child attributes (key/value pair). Or the entire parent object with all the objects in it. Need to get the parent names i've mentioned above.
How can I do this?
Thanks in advance.
Iterating the object should work:
var parents = {
"parent": {
"child-parent-1": {
"att1": null,
"att2": null,
},
"child-parent-2": {
"att1": null,
"att2": null,
}
}
}
for(var key in parents.parent){ // parents.parent because the children are in a object in `parents`
console.log(key); // child-parent-1 / child-parent-2
console.log(parents.parent[key]); // The objects themselves.
}
For me, this logs:
// child-parent-1
// Object {att1: null, att2: null}
// child-parent-2
// Object {att1: null, att2: null}