Fuzzy search deep array only on certain properties - javascript

I have a JSON dataset which could be very large when it returns, with the following structure for each object:
{
"ctr": 57,
"averageECPC": 23,
"cost": 2732.54,
"margin": 66,
"profit": 2495.9,
"property": {
"value": "Izzby",
"uri": "/Terrago/2"
},
"status": {
"content": "<p>Some Content</p>",
"stage": 1
},
"alerts": {
"status": 2
},
"revenue": {
"value": 2573.13,
"compare": 0
},
"children": [{
"ctr": 79,
"averageECPC": 54,
"cost": 3554.78,
"margin": 88,
"profit": 3145.81,
"property": {
"value": "Comvex",
"uri": "/Octocore/4"
},
"status": {
"content": "<p>Some Content</p>",
"stage": 1
},
"alerts": {
"status": 2
},
"revenue": {
"value": 1247.92,
"compare": 0
}
}]
}
Now I want to search all objects in the array and return only objects which include a string of some sort, but I only want to search certain properties.
I basically have another array which contains the keys I want to search, e.g.
const iteratees = ['ctr', 'property.value', 'status.stage']
I have lodash available within the project, but I have no idea where to start.
Any ideas?

You could use filter(), some() and reduce() to do this.
const iteratees = ['ctr', 'property.value', 'status.stage'];
var searchFor = 'lo';
var result = arr.filter(function(o) {
return iteratees.some(function(e) {
var res = e.split('.').reduce(function(a, b) {
if(a) return a[b];
}, o);
if(res) {
if((res).toString().indexOf(searchFor) != -1) return true;
}
})
})
var arr = [{
"ctr": 'lorem',
"averageECPC": 23,
"cost": 2732.54,
"margin": 66,
"profit": 2495.9,
"property": {
"value": "Izzby",
"uri": "/Terrago/2"
},
"status": {
"content": "<p>Some Content</p>",
"stage": 1
},
"alerts": {
"status": 2
},
"revenue": {
"value": 2573.13,
"compare": 0
},
"children": [{
"ctr": 79,
"averageECPC": 54,
"cost": 3554.78,
"margin": 88,
"profit": 3145.81,
"property": {
"value": "Comvex",
"uri": "/Octocore/4"
},
"status": {
"content": "<p>Some Content</p>",
"stage": 1
},
"alerts": {
"status": 2
},
"revenue": {
"value": 1247.92,
"compare": 0
}
}]
}, {
name: 'lorem',
ctr: 12,
property: {
value: 1
},
status: {
stage: 1
}
}, {
name: 'ipsum'
}]
const iteratees = ['ctr', 'property.value', 'status.stage'];
var searchFor = 'lo';
var result = arr.filter(function(o) {
return iteratees.some(function(e) {
var res = e.split('.').reduce(function(a, b) {
if (a) return a[b];
}, o);
if (res) {
if ((res).toString().indexOf(searchFor) != -1) return true;
}
})
})
console.log(result)

Related

Can't loop array after grouping with .reduce

I've got the following meetings object :
[
{
"id": 19,
"duration": 1.75,
"Employee": {
"name": "Jeanne",
}
},
{
"id": 20,
"duration": 1.00,
"Employee": {
"name": "Louis",
}
},
{
"id": 21,
"duration": 1.00,
"Employee": {
"name": "Jeanne",
}
}
]
I want to group it by Employee.name. Using reduce() here is what I come up with :
meetings.reduce(function (r, a) {
r[a.Employee.name] = r[a.Employee.name] || [];
r[a.Employee.name].push(a);
return r;
}
The resulting object is the following :
{
"Jeanne": [
{
"id": 19,
"duration": 1.75,
"Employee": {
"name": "Jeanne"
}
},
{
"id": 21,
"duration": 1.00,
"Employee": {
"name": "Jeanne"
}
}
],
"Louis": [
{
"id": 20,
"duration": 1.00,
"Employee": {
"name": "Louis"
}
}
]
}
If I try to map() or forEach() i cannot get the value of the element :
Array.from(thisMeeting).forEach(element => console.log(element));
return `undefined`;
Array.from-ming an Object will result in an empty array.
You'll have to iterate over the objects keys with Object.entries(thisMeeting).forEach… and grab the values inside that.

Create new Array of object based on the Property Value

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)

Flatten an object using lodash

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.

remove elements from nested object array

I want to remove object based on conditional check from the JSON object using angularjs/jQuery.
I tried with below code but output is not as expected.
Demo: https://plnkr.co/edit/EWwbETITqn7G79Xypt0g?p=preview
angular.module('ui.bootstrap.demo').controller('DataCtrl', function ($scope) {
$scope.responseData = {
"data": [{
"name": "Machine", "quantity": 20, "snVal": 22,
"machine1": [{ "id": 2009, "machineName": "ASD1", "trackID": "34219", "status": "delivered" },
{ "id": 27893, "machineName": "PX20AA", "trackID": "3422", "status": "avail" }],
"machine2": [{ "id": 1023, "machineName": "XY22", "trackID": "1345", "status": "avail" },
{ "id": 1233, "machineName": "PP3DF", "trackID": "112", "status": "delivered" }
]
}]
}
console.log("R1 :: " + JSON.stringify($scope.responseData));
$scope.newResponse = $.grep($scope.responseData.data, function (element, index) { return element.status == "delivered" }, true);
console.log("R2 after removing elements:: " + JSON.stringify($scope.newResponse));
});
Try this,
let responseData = { "data": [{ "name": "Machine", "quantity": 20, "snVal": 22, "machine1": [{ "id": 2009, "machineName": "ASD1", "trackID": "34219", "status": "delivered" }, { "id": 27893, "machineName": "PX20AA", "trackID": "3422", "status": "avail" }], "machine2": [{ "id": 1023, "machineName": "XY22", "trackID": "1345", "status": "avail" }, { "id": 1233, "machineName": "PP3DF", "trackID": "112", "status": "delivered" }] }] } ;
let newResponse = responseData;
newResponse.data.forEach(function (item) {
for (j in item) {
if (j.includes("machine")) {
//better you check if type is array, using Object.prototype.toString.call(j) === "[object Array]"
item[j] = item[j].reduce(function (acc, machine) {
if (machine.status !== "delivered"){
acc.push(machine);
}
return acc;
}, []);
}
}
})|
console.log(newResponse);
Here we are just iterating through all objects in the data field. Since properties like machine1, machine2 is an array, we iterate through it and filter all machines which are not delivered.
You must note that I have used a for-in loop and array reduce() method here.

Filter and clone object properties

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);

Categories

Resources