I want to create a new Array of objects based on Interface Value.
Like we need to group objects with the same Interface value. The new array would be like two new Objects with the same interface value. So here in the new generated array of objects, there would be two objects. Such as GE5 and GE6.I have a limitation to use only ES5.
There should be a looping logic
Logic
Loop through the data array. Which is the input.
Loop through cloudServices nodes in each node of the data and find the distict value.
Loop through this distinct values and and generate a group of each distict value using Array.filter.
Aggregate all the remainig values from each node in data array except the cloudServices node.
Generate a final object with this remaining values and the above generated group.
ES5 implementation
var data = [{ "id": 14042, "created": "2020-03-18T10:11:40.000Z", "enterpriseId": 437, "siteId": 6302, "activationKey": "PMZP-NGRU-HE64-SA5M", "activationKeyExpires": "2021-08-04T16:21:33.000Z", "activationState": "ACTIVATED", "activationTime": "2020-03-18T17:05:27.000Z", "softwareVersion": "4.3.0", "buildNumber": "R430-20210720-GA-64951-67694-6911a00421", "factorySoftwareVersion": "3.3.0", "factoryBuildNumber": "R330-MTHD-20190328-GA", "softwareUpdated": "2021-09-24T11:21:49.000Z", "selfMacAddress": "50:9a:4c:e4:1e:c0", "deviceId": "93AB7D33-87B7-42AA-BC0B-7D8255E069AD", "logicalId": "d25a6121-bf16-4512-b490-2dc5c45e11b8", "serialNumber": "F0TFXC2", "modelNumber": "edge610", "deviceFamily": "EDGE6X0", "name": "SDALM-BAYNARD-LAB-4", "dnsName": null, "description": "Dual Internet Site in Baynard", "alertsEnabled": 1, "operatorAlertsEnabled": 1, "edgeState": "CONNECTED", "edgeStateTime": "2021-09-24T11:23:00.000Z", "isLive": 0, "systemUpSince": "2021-09-24T11:20:55.000Z", "serviceUpSince": "2021-09-24T11:31:06.000Z", "lastContact": "2021-10-04T14:06:47.000Z", "serviceState": "IN_SERVICE", "endpointPkiMode": "CERTIFICATE_REQUIRED", "haState": "UNCONFIGURED", "haPreviousState": "UNCONFIGURED", "haLastContact": "0000-00-00 00:00:00", "haSerialNumber": null, "bastionState": "UNCONFIGURED", "modified": "2021-10-04T14:06:47.000Z", "customInfo": "", "isHub": false, "cloudServices": [{ "state": "UP", "timestamp": "2021-10-04T14:01:50.638Z", "link": "00000005-bf16-4512-b490-2dc5c45e11b8", "local_interface_ip": "172.16.2.1", "local_public_ip": "217.38.39.43", "nvs_ip": "165.225.16.236", "pathId": "211262ED9DE488A22CFEBBA9809092B32B937912", "segmentId": 0, "segmentLogicalId": "cd948075-e95f-4c7c-beb2-0fcde7e17c62", "l7_check": "UP", "l7_check_rtt": { "max": 11, "avg": 7, "min": 5 }, "site": { "id": 60282, "logicalId": "717f67c5-7426-4689-a74c-b58c93d4c3b1", "data": { "customSourceIp": "", "linkInternalLogicalId": "00000005-bf16-4512-b490-2dc5c45e11b8", "primaryAddressing": { "internalRouterIp": "172.22.60.145", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.146", "internalZenMask": "255.255.255.255" }, "secondaryAddressing": { "internalRouterIp": "172.22.60.149", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.150", "internalZenMask": "255.255.255.255" }, "useCustomSourceIp": false } }, "provider": { "name": "L7HC-LON3-MAN1-GRE", "id": 549697, "logicalId": "d5a058dc-6202-494c-b65d-6a8c273ed1c4", "data": { "primaryServer": "165.225.16.236", "secondaryServer": "165.225.196.39", "automateDeployment": false, "enableTunnels": true, "sharedIkeAuth": false, "maxTunnelsPerIkeIdentity": 128, "l7HealthCheck": { "enabled": true, "probeIntervalSec": 5, "numOfRetries": 3, "rttThresholdMs": 3000, "cloud": "zscloud.net" }, "provider": "zscalerWebSecurityService" } }, "segmentName": "Global Segment", "interface": "GE5" }, { "state": "STANDBY", "timestamp": "2021-10-04T14:01:50.638Z", "link": "00000005-bf16-4512-b490-2dc5c45e11b8", "local_interface_ip": "172.16.2.1", "local_public_ip": "217.38.39.43", "nvs_ip": "165.225.196.39", "pathId": "26434D16946CFD147D5DDFA50647F48A0066AB31", "segmentId": 0, "segmentLogicalId": "cd948075-e95f-4c7c-beb2-0fcde7e17c62", "l7_check": "UP", "l7_check_rtt": { "max": 10, "avg": 6, "min": 5 }, "site": { "id": 60282, "logicalId": "717f67c5-7426-4689-a74c-b58c93d4c3b1", "data": { "customSourceIp": "", "linkInternalLogicalId": "00000005-bf16-4512-b490-2dc5c45e11b8", "primaryAddressing": { "internalRouterIp": "172.22.60.145", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.146", "internalZenMask": "255.255.255.255" }, "secondaryAddressing": { "internalRouterIp": "172.22.60.149", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.150", "internalZenMask": "255.255.255.255" }, "useCustomSourceIp": false } }, "provider": { "name": "L7HC-LON3-MAN1-GRE", "id": 549697, "logicalId": "d5a058dc-6202-494c-b65d-6a8c273ed1c4", "data": { "primaryServer": "165.225.16.236", "secondaryServer": "165.225.196.39", "automateDeployment": false, "enableTunnels": true, "sharedIkeAuth": false, "maxTunnelsPerIkeIdentity": 128, "l7HealthCheck": { "enabled": true, "probeIntervalSec": 5, "numOfRetries": 3, "rttThresholdMs": 3000, "cloud": "zscloud.net" }, "provider": "zscalerWebSecurityService" } }, "segmentName": "Global Segment", "interface": "GE5" }, { "state": "STANDBY", "timestamp": "2021-10-04T14:01:50.638Z", "link": "00000006-bf16-4512-b490-2dc5c45e11b8", "local_interface_ip": "172.16.1.1", "local_public_ip": "217.38.39.41", "nvs_ip": "165.225.196.39", "pathId": "9B88047C891952D8A661F30A8E7C0A5842AB8544", "segmentId": 0, "segmentLogicalId": "cd948075-e95f-4c7c-beb2-0fcde7e17c62", "l7_check": "UP", "l7_check_rtt": { "max": 16, "avg": 6, "min": 5 }, "site": { "id": 60282, "logicalId": "717f67c5-7426-4689-a74c-b58c93d4c3b1", "data": { "customSourceIp": "", "linkInternalLogicalId": "00000005-bf16-4512-b490-2dc5c45e11b8", "primaryAddressing": { "internalRouterIp": "172.22.60.145", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.146", "internalZenMask": "255.255.255.255" }, "secondaryAddressing": { "internalRouterIp": "172.22.60.149", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.150", "internalZenMask": "255.255.255.255" }, "useCustomSourceIp": false } }, "provider": { "name": "L7HC-LON3-MAN1-GRE", "id": 549697, "logicalId": "d5a058dc-6202-494c-b65d-6a8c273ed1c4", "data": { "primaryServer": "165.225.16.236", "secondaryServer": "165.225.196.39", "automateDeployment": false, "enableTunnels": true, "sharedIkeAuth": false, "maxTunnelsPerIkeIdentity": 128, "l7HealthCheck": { "enabled": true, "probeIntervalSec": 5, "numOfRetries": 3, "rttThresholdMs": 3000, "cloud": "zscloud.net" }, "provider": "zscalerWebSecurityService" } }, "segmentName": "Global Segment", "interface": "GE6" }, { "state": "UP", "timestamp": "2021-10-04T14:01:50.638Z", "link": "00000006-bf16-4512-b490-2dc5c45e11b8", "local_interface_ip": "172.16.1.1", "local_public_ip": "217.38.39.41", "nvs_ip": "165.225.16.236", "pathId": "DB965CA91A564DE09027F8D766F92CD0DDB54405", "segmentId": 0, "segmentLogicalId": "cd948075-e95f-4c7c-beb2-0fcde7e17c62", "l7_check": "UP", "l7_check_rtt": { "max": 1063, "avg": 41, "min": 5 }, "site": { "id": 60282, "logicalId": "717f67c5-7426-4689-a74c-b58c93d4c3b1", "data": { "customSourceIp": "", "linkInternalLogicalId": "00000005-bf16-4512-b490-2dc5c45e11b8", "primaryAddressing": { "internalRouterIp": "172.22.60.145", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.146", "internalZenMask": "255.255.255.255" }, "secondaryAddressing": { "internalRouterIp": "172.22.60.149", "internalRouterMask": "255.255.255.255", "internalZenIp": "172.22.60.150", "internalZenMask": "255.255.255.255" }, "useCustomSourceIp": false } }, "provider": { "name": "L7HC-LON3-MAN1-GRE", "id": 549697, "logicalId": "d5a058dc-6202-494c-b65d-6a8c273ed1c4", "data": { "primaryServer": "165.225.16.236", "secondaryServer": "165.225.196.39", "automateDeployment": false, "enableTunnels": true, "sharedIkeAuth": false, "maxTunnelsPerIkeIdentity": 128, "l7HealthCheck": { "enabled": true, "probeIntervalSec": 5, "numOfRetries": 3, "rttThresholdMs": 3000, "cloud": "zscloud.net" }, "provider": "zscalerWebSecurityService" } }, "segmentName": "Global Segment", "interface": "GE6" }] }];
//Function to find distinct valies of an object array with specific key
function distinct(dataArray, key) {
var distinctList = [];
dataArray.forEach(function (node) {
if (distinctList.indexOf(node[key]) === -1) {
distinctList.push(node[key]);
}
});
return distinctList;
}
// Reference https://stackoverflow.com/a/34710102/6099327
function _objectWithoutProperties(obj, keys) {
var target = {};
for (var i in obj) {
if (keys.indexOf(i) >= 0) {
continue;
}
if (!Object.prototype.hasOwnProperty.call(obj, i)) {
continue;
}
target[i] = obj[i];
}
return target;
}
var parsedOutput = [];
data.forEach(function (dataNode) {
var distinctInterfaces = distinct(dataNode.cloudServices, "interface");
var remainingProperties = _objectWithoutProperties(dataNode, ["cloudServices"]);
var output = remainingProperties;
distinctInterfaces.forEach(function (interface) {
output[interface] = dataNode.cloudServices.filter(function (node) {
return node.interface === interface;
});
});
parsedOutput.push(output);
});
console.log(parsedOutput);
ES6 Implementation will be a little more easy
const data = [{"id":14042,"created":"2020-03-18T10:11:40.000Z","enterpriseId":437,"siteId":6302,"activationKey":"PMZP-NGRU-HE64-SA5M","activationKeyExpires":"2021-08-04T16:21:33.000Z","activationState":"ACTIVATED","activationTime":"2020-03-18T17:05:27.000Z","softwareVersion":"4.3.0","buildNumber":"R430-20210720-GA-64951-67694-6911a00421","factorySoftwareVersion":"3.3.0","factoryBuildNumber":"R330-MTHD-20190328-GA","softwareUpdated":"2021-09-24T11:21:49.000Z","selfMacAddress":"50:9a:4c:e4:1e:c0","deviceId":"93AB7D33-87B7-42AA-BC0B-7D8255E069AD","logicalId":"d25a6121-bf16-4512-b490-2dc5c45e11b8","serialNumber":"F0TFXC2","modelNumber":"edge610","deviceFamily":"EDGE6X0","name":"SDALM-BAYNARD-LAB-4","dnsName":null,"description":"Dual Internet Site in Baynard","alertsEnabled":1,"operatorAlertsEnabled":1,"edgeState":"CONNECTED","edgeStateTime":"2021-09-24T11:23:00.000Z","isLive":0,"systemUpSince":"2021-09-24T11:20:55.000Z","serviceUpSince":"2021-09-24T11:31:06.000Z","lastContact":"2021-10-04T14:06:47.000Z","serviceState":"IN_SERVICE","endpointPkiMode":"CERTIFICATE_REQUIRED","haState":"UNCONFIGURED","haPreviousState":"UNCONFIGURED","haLastContact":"0000-00-00 00:00:00","haSerialNumber":null,"bastionState":"UNCONFIGURED","modified":"2021-10-04T14:06:47.000Z","customInfo":"","isHub":false,"cloudServices":[{"state":"UP","timestamp":"2021-10-04T14:01:50.638Z","link":"00000005-bf16-4512-b490-2dc5c45e11b8","local_interface_ip":"172.16.2.1","local_public_ip":"217.38.39.43","nvs_ip":"165.225.16.236","pathId":"211262ED9DE488A22CFEBBA9809092B32B937912","segmentId":0,"segmentLogicalId":"cd948075-e95f-4c7c-beb2-0fcde7e17c62","l7_check":"UP","l7_check_rtt":{"max":11,"avg":7,"min":5},"site":{"id":60282,"logicalId":"717f67c5-7426-4689-a74c-b58c93d4c3b1","data":{"customSourceIp":"","linkInternalLogicalId":"00000005-bf16-4512-b490-2dc5c45e11b8","primaryAddressing":{"internalRouterIp":"172.22.60.145","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.146","internalZenMask":"255.255.255.255"},"secondaryAddressing":{"internalRouterIp":"172.22.60.149","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.150","internalZenMask":"255.255.255.255"},"useCustomSourceIp":false}},"provider":{"name":"L7HC-LON3-MAN1-GRE","id":549697,"logicalId":"d5a058dc-6202-494c-b65d-6a8c273ed1c4","data":{"primaryServer":"165.225.16.236","secondaryServer":"165.225.196.39","automateDeployment":false,"enableTunnels":true,"sharedIkeAuth":false,"maxTunnelsPerIkeIdentity":128,"l7HealthCheck":{"enabled":true,"probeIntervalSec":5,"numOfRetries":3,"rttThresholdMs":3000,"cloud":"zscloud.net"},"provider":"zscalerWebSecurityService"}},"segmentName":"Global Segment","interface":"GE5"},{"state":"STANDBY","timestamp":"2021-10-04T14:01:50.638Z","link":"00000005-bf16-4512-b490-2dc5c45e11b8","local_interface_ip":"172.16.2.1","local_public_ip":"217.38.39.43","nvs_ip":"165.225.196.39","pathId":"26434D16946CFD147D5DDFA50647F48A0066AB31","segmentId":0,"segmentLogicalId":"cd948075-e95f-4c7c-beb2-0fcde7e17c62","l7_check":"UP","l7_check_rtt":{"max":10,"avg":6,"min":5},"site":{"id":60282,"logicalId":"717f67c5-7426-4689-a74c-b58c93d4c3b1","data":{"customSourceIp":"","linkInternalLogicalId":"00000005-bf16-4512-b490-2dc5c45e11b8","primaryAddressing":{"internalRouterIp":"172.22.60.145","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.146","internalZenMask":"255.255.255.255"},"secondaryAddressing":{"internalRouterIp":"172.22.60.149","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.150","internalZenMask":"255.255.255.255"},"useCustomSourceIp":false}},"provider":{"name":"L7HC-LON3-MAN1-GRE","id":549697,"logicalId":"d5a058dc-6202-494c-b65d-6a8c273ed1c4","data":{"primaryServer":"165.225.16.236","secondaryServer":"165.225.196.39","automateDeployment":false,"enableTunnels":true,"sharedIkeAuth":false,"maxTunnelsPerIkeIdentity":128,"l7HealthCheck":{"enabled":true,"probeIntervalSec":5,"numOfRetries":3,"rttThresholdMs":3000,"cloud":"zscloud.net"},"provider":"zscalerWebSecurityService"}},"segmentName":"Global Segment","interface":"GE5"},{"state":"STANDBY","timestamp":"2021-10-04T14:01:50.638Z","link":"00000006-bf16-4512-b490-2dc5c45e11b8","local_interface_ip":"172.16.1.1","local_public_ip":"217.38.39.41","nvs_ip":"165.225.196.39","pathId":"9B88047C891952D8A661F30A8E7C0A5842AB8544","segmentId":0,"segmentLogicalId":"cd948075-e95f-4c7c-beb2-0fcde7e17c62","l7_check":"UP","l7_check_rtt":{"max":16,"avg":6,"min":5},"site":{"id":60282,"logicalId":"717f67c5-7426-4689-a74c-b58c93d4c3b1","data":{"customSourceIp":"","linkInternalLogicalId":"00000005-bf16-4512-b490-2dc5c45e11b8","primaryAddressing":{"internalRouterIp":"172.22.60.145","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.146","internalZenMask":"255.255.255.255"},"secondaryAddressing":{"internalRouterIp":"172.22.60.149","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.150","internalZenMask":"255.255.255.255"},"useCustomSourceIp":false}},"provider":{"name":"L7HC-LON3-MAN1-GRE","id":549697,"logicalId":"d5a058dc-6202-494c-b65d-6a8c273ed1c4","data":{"primaryServer":"165.225.16.236","secondaryServer":"165.225.196.39","automateDeployment":false,"enableTunnels":true,"sharedIkeAuth":false,"maxTunnelsPerIkeIdentity":128,"l7HealthCheck":{"enabled":true,"probeIntervalSec":5,"numOfRetries":3,"rttThresholdMs":3000,"cloud":"zscloud.net"},"provider":"zscalerWebSecurityService"}},"segmentName":"Global Segment","interface":"GE6"},{"state":"UP","timestamp":"2021-10-04T14:01:50.638Z","link":"00000006-bf16-4512-b490-2dc5c45e11b8","local_interface_ip":"172.16.1.1","local_public_ip":"217.38.39.41","nvs_ip":"165.225.16.236","pathId":"DB965CA91A564DE09027F8D766F92CD0DDB54405","segmentId":0,"segmentLogicalId":"cd948075-e95f-4c7c-beb2-0fcde7e17c62","l7_check":"UP","l7_check_rtt":{"max":1063,"avg":41,"min":5},"site":{"id":60282,"logicalId":"717f67c5-7426-4689-a74c-b58c93d4c3b1","data":{"customSourceIp":"","linkInternalLogicalId":"00000005-bf16-4512-b490-2dc5c45e11b8","primaryAddressing":{"internalRouterIp":"172.22.60.145","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.146","internalZenMask":"255.255.255.255"},"secondaryAddressing":{"internalRouterIp":"172.22.60.149","internalRouterMask":"255.255.255.255","internalZenIp":"172.22.60.150","internalZenMask":"255.255.255.255"},"useCustomSourceIp":false}},"provider":{"name":"L7HC-LON3-MAN1-GRE","id":549697,"logicalId":"d5a058dc-6202-494c-b65d-6a8c273ed1c4","data":{"primaryServer":"165.225.16.236","secondaryServer":"165.225.196.39","automateDeployment":false,"enableTunnels":true,"sharedIkeAuth":false,"maxTunnelsPerIkeIdentity":128,"l7HealthCheck":{"enabled":true,"probeIntervalSec":5,"numOfRetries":3,"rttThresholdMs":3000,"cloud":"zscloud.net"},"provider":"zscalerWebSecurityService"}},"segmentName":"Global Segment","interface":"GE6"}]}];
const parsedOutput = data.map((node) => {
const { cloudServices, ...otherNodes } = node;
const uniqueInterfaces = [ ...new Set(cloudServices.map(service => service.interface)) ];
interfaceObj = uniqueInterfaces.reduce((acc, curr) => {
acc[curr] = cloudServices.filter((node) => node.interface === curr);
return acc;
}, {})
return { ...otherNodes, ...interfaceObj };
});
console.log(parsedOutput)
I have below this nested object
I need to create an array using this object containing keys. And if keys are object then it should use .dot syntax. and if it is an array then it should give me key.0.keyName. Is it possible to do so?
Output
[
"AllowIPNPayment",
"AllowOnlinePayment",
"MetaData.CreateTime",
"MetaData.LastUpdatedTime",
"CustomField.0.DefinitionId",
"CustomField.0.Name",
"CustomField.0.Type",
...
]
What I have tried is just ugly and does give me expected result. If it is possible with more concise way.
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 }
let object = {}
for (let k in invoiceObject) {
if (typeof invoiceObject[k] === "object") {
object[k] = {};
for (let l in invoiceObject[k]) {
object[k][l] = "";
}
} else if (typeof invoiceObject[k] === "array") {
object[k] = [];
for (let l in invoiceObject[k][0]) {
object[k][l] = "";
}
} else {
object[k] = "";
}
}
console.log(object)
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)
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;
}
You could solve this with a recursive function. The function below keeps track of the current keys, and joins them as soon as an end point is reached (a non-object or empty object/array).
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 };
function getDotKeys(item, keys = []) {
const isObject = item && typeof item == "object";
if (!isObject) return Array.of(keys.join("."));
const pairs = Array.isArray(item)
? item.map((value, index) => [index, value])
: Object.entries(item);
const isEmpty = !pairs.length;
if (isEmpty) return Array.of(keys.join("."));
const result = [];
for (const [key, value] of pairs) {
const dotKeys = getDotKeys(value, [...keys, key]);
result.push(...dotKeys);
}
return result;
}
console.log(getDotKeys(invoiceObject));
This does produce a different result than what you have in your question, since your solution stops at the second level for objects and third level for arrays. This solution also includes more then only index 0.
I have 2 arrays of objects: itemsList and itemsFetched. All of the objects inside each array have the same structure (nr of key/values). One of those keys has the same 'meaning' but a different name (item_id on itemsList, id on itemsFetched ). Their values are the same.
I need to filter the itemsList array and leave only the objects that have the item_id value equal to the id value on itemsFetched. Then copy(add) the key/value count from each object on the itemsFetched array (which matches the item_id=id) to the filtered array.
I've a working code but I'm sure it isnt the best way to solve this problem. I've already asked something similar before (regarding the 'filter' part) which solved my problem, but since I had to add the 'count' part after the filtering, I ended up refactoring the whole thing.
itemsList (sample)
[
{
"id": 0,
"name": "Egg",
"img": "http://www.serebii.net/pokemongo/items/egg.png"
},
{
"id": 1,
"name": "Pokeball",
"img": "http://www.serebii.net/pokemongo/items/20pokeballs.png"
},
{
"id": 2,
"name": "Greatball",
"img": "http://www.serebii.net/pokemongo/items/greatball.png"
},
{
"id": 401,
"name": "Incense",
"img": "http://www.serebii.net/pokemongo/items/incense.png"
},
{
"id": 901,
"name": "Incubator (Unlimited)",
"img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
}
]
itemsFetched (sample)
[
{
"item_id": 1,
"count": 50,
"unseen": true
},
{
"item_id": 401,
"count": 2,
"unseen": true
},
{
"item_id": 901,
"count": 1,
"unseen": true
}
]
resultArray (what I want in the end)
[
{
"id": 1,
"name": "Pokeball",
"count": 50,
"img": "http://www.serebii.net/pokemongo/items/20pokeballs.png",
},
{
"id": 401,
"name": "Incense",
"count": 2,
"img": "http://www.serebii.net/pokemongo/items/incense.png"
},
{
"id": 901,
"name": "Incubator (Unlimited)",
"count": 1,
"img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
}
]
my current code (working)
let arr = [];
itemsFetched.forEach((item) => {
itemsList.forEach((item2) => {
if (item.item_id === item2.id) {
arr.push({
"id": item.item_id,
"name": item2.name,
"count": item.count,
"img": item2.img
});
}
});
});
PS: I'm able to use ES6/7 syntax/features.
You can use hash map to reduce Time complexitly, your algorithm is O(m*n), The follow is O(m+n+r)
const itemsMap = itemsList.reduce((map, item) => {
map[item.id] = item
return map
}, {})
const results = itemsFetched
.filter((item) => itemsMap.hasOwnProperty(item.item_id))
.map((item) => ({
id: item.item_id,
name: itemsMap[item.item_id].name,
count: item.count,
img: itemsMap[item.item_id].img,
}))
Use a for ... of loop (an ES6 feature) in conjunction with Array#map.
This makes it much easier to return the merged object the first time you find a match, which is a logically optimization because neither list should contain more than one entry with a given id.
const result = itemsFetched.map(data => {
for (let item of itemsList) {
if (data.item_id === item.id) {
return {
id: item.id,
name: item.name,
count: data.count,
img: item.img
}
}
}
})
Snippet:
const itemsList = [{
"id": 0,
"name": "Egg",
"img": "http://www.serebii.net/pokemongo/items/egg.png"
}, {
"id": 1,
"name": "Pokeball",
"img": "http://www.serebii.net/pokemongo/items/20pokeballs.png"
}, {
"id": 2,
"name": "Greatball",
"img": "http://www.serebii.net/pokemongo/items/greatball.png"
}, {
"id": 401,
"name": "Incense",
"img": "http://www.serebii.net/pokemongo/items/incense.png"
}, {
"id": 901,
"name": "Incubator (Unlimited)",
"img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
}]
const itemsFetched = [{
"item_id": 1,
"count": 50,
"unseen": true
}, {
"item_id": 401,
"count": 2,
"unseen": true
}, {
"item_id": 901,
"count": 1,
"unseen": true
}]
const result = itemsFetched.map(data => {
for (let item of itemsList) {
if (data.item_id === item.id) {
return {
id: item.id,
name: item.name,
count: data.count,
img: item.img
}
}
}
})
console.log(result)
One way to improve is to use for..of statement instead of forEach for the inner loop. This helps break from the loop once the id matches. There is no direct way to break from forEach method.
let arr = [];
itemsFetched.forEach((item) => {
for (let item2 of itemsList) {
if (itemsFetched.item_id === itemsList.id) {
arr.push({
"id": itemsFetched.item_id,
"name": itemsList.name,
"count": itemsFetched.count,
"img": itemsList.img
});
break;
}
}
});
Like this?
var itemsList = [
{
"id": 0,
"name": "Egg",
"img": "http://www.serebii.net/pokemongo/items/egg.png"
},
{
"id": 1,
"name": "Pokeball",
"img": "http://www.serebii.net/pokemongo/items/20pokeballs.png"
},
{
"id": 2,
"name": "Greatball",
"img": "http://www.serebii.net/pokemongo/items/greatball.png"
},
{
"id": 401,
"name": "Incense",
"img": "http://www.serebii.net/pokemongo/items/incense.png"
},
{
"id": 901,
"name": "Incubator (Unlimited)",
"img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
}
];
var itemsFetched = [
{
"item_id": 1,
"count": 50,
"unseen": true
},
{
"item_id": 401,
"count": 2,
"unseen": true
},
{
"item_id": 901,
"count": 1,
"unseen": true
}
]
let arr = [];
itemsFetched.forEach((item) => {
itemsList.forEach((item2) => {
if (item.item_id == item2.id) {
arr.push({
"id": item.item_id,
"name": item2.name,
"count": item.count,
"img": item2.img
});
}
});
});
console.log(arr);