Addition keys in JSON [closed] - javascript

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I need to make addition using NodeJS in an array JSON and then return the altered JSON like this, I need also check if key exist or not to avoid exceptions:
JSON:
{
"cmd": [
{
"sales": [
{
"qte1": "2",
"qte2": "3",
"someString": "test
},
{
"qte1": "66",
"someAttribute": "test "
},
{
"qte2": "77",
"toto": "tata"
}
]
}
]
}
target JSON:
{
"cmd": [
{
"sales": [
{
"qte1": "2",
"qte2": "3",
"somme": "5"
},
{
"qte1": "66",
"somme": "66"
},
{
"qte2": "77",
"somme": "77"
}
]
}
]
}
I need to add the two key qte1 et qte2
would you have any propositions ?
Best regards

Seems like you just want the sum of the existing keys, should be pretty simple using a couple .map commands and a .reduce:
return json.cmd.map(function(salesList) {
return salesList.sales.map(function(sale) {
var keysToAdd = ["qte1", "qte2"];
sale.somme = Object.keys(sale).reduce(function(total, key) {
return total += keysToAdd.indexOf(key) > -1 ? +sale[key] : 0;
}, 0);
return sale;
});
});
Demo: https://jsfiddle.net/x294yt1h/

const data =
{
"cmd": [
{
"sales": [
{
"qte1": "2",
"qte2": "3"
},
{
"qte1": "66"
},
{
"qte2": "77"
}
]
}
]
};
function sum(dataObj) {
const hasCmd = dataObj && dataObj.cmd && dataObj.cmd.length > 0;
const hasSales = hasCmd && dataObj.cmd[0].sales && dataObj.cmd[0].sales.length > 0;
if (hasCmd && hasSales) {
const clonedArray = dataObj.cmd[0].sales.slice();
const summedArray = clonedArray.map(function(group) {
const groupKeys = Object.keys(group);
const sum = groupKeys.reduce(function (total, key) {
return total + parseInt(group[key], 10 /* Decimal Radix */);
}, 0);
return Object.assign({}, group, { 'somme': sum.toString() });
});
// build a new object to return to include new summed array
return { "cmd": [{ "sales": summedArray }] };
}
return dataObj;
}
console.log('data', JSON.stringify(data));
const newData = sum(data);
console.log('newData', JSON.stringify(newData));

Maybe you can first and formost refector your tree.
Like that :
{
command: [
{
sales: [
{
quantity: [1, 2, 4],
sum: 7
}
]
}
]
}
I don't know if your structure is open to any refectoring, but you must do something about it !
However, try to use the correct type of value in your row, and try to keep in mind to never mutate and object, use functor like map and reduce :
const cmd = [
{
sales: [
{
quantity: [1, 2, 3],
sum: 0
},
{
quantity: [67, 2, 3],
sum: 0
}
]
}
];
const newObjectWithSum = cmd.map(sales => {
return sales.sales.map((sale) => {
sale.sum = sale.quantity.reduce((valueIn, next) => {
return valueIn + next;
},0);
return sale;
});
})

Related

Retrieving data from a complex inconsistent JSON

I'm trying to set variables from a JSON object that I retrieve with a POST query. But the results aren't returned in the same order every time, so it doesn't always work. I'm not sure how to correctly set my variables with the array positions not remaining constant:
var idle = Example1.results[0].data[1].stats.count;
var waiting = Example1.results[1].data[0].stats.count;
(i.e. This works on example 1, but not example 2)
Example1 = {"results":[{"group":{"queueId":"someID"},"data":[{"metric":"oOnQueueUsers","qualifier":"INTERACTING","stats":{"count":2}},{"metric":"oOnQueueUsers","qualifier":"IDLE","stats":{"count":5}}]},{"group":{"queueId":"someID","mediaType":"voice"},"data":[{"metric":"oWaiting","stats":{"count":0}}]}]}
Example2 = {"results":[{"group":{"queueId":"someID","mediaType":"voice"},"data":[{"metric":"oWaiting","stats":{"count":1}}]},{"group":{"queueId":"someID"},"data":[{"metric":"oOnQueueUsers","qualifier":"INTERACTING","stats":{"count":4}},{"metric":"oOnQueueUsers","qualifier":"IDLE","stats":{"count":6}}]}]}
You can use find() and some() to get the result you want.
const example1 = { results: [ { group: { queueId: "someID" }, data: [ { metric: "oOnQueueUsers", qualifier: "INTERACTING", stats: { count: 2 }, }, { metric: "oOnQueueUsers", qualifier: "IDLE", stats: { count: 5 } }, ], }, { group: { queueId: "someID", mediaType: "voice" }, data: [{ metric: "oWaiting", stats: { count: 0 } }], }, ], };
const example2 = { results: [ { group: { queueId: "someID", mediaType: "voice" }, data: [{ metric: "oWaiting", stats: { count: 1 } }], }, { group: { queueId: "someID" }, data: [ { metric: "oOnQueueUsers", qualifier: "INTERACTING", stats: { count: 4 }, }, { metric: "oOnQueueUsers", qualifier: "IDLE", stats: { count: 6 } }, ], }, ], };
const idle1 = example1.results
.find(a => a.data.some(d => d.qualifier === "IDLE"))
.data.find(b => b.qualifier === "IDLE").stats.count;
const waiting1 = example1.results
.find(a => a.data.some(d => d.metric === "oWaiting"))
.data.find(b => b.metric === "oWaiting").stats.count;
const idle2 = example2.results
.find(a => a.data.some(d => d.qualifier === "IDLE"))
.data.find(b => b.qualifier === "IDLE").stats.count;
const waiting2 = example2.results
.find(a => a.data.some(d => d.metric === "oWaiting"))
.data.find(b => b.metric === "oWaiting").stats.count;
console.log({ idle1 }, { waiting1 }, { idle2 }, { waiting2 });
If you cannot depend on the order being the same every time... or given your example data that each object doesn't even have the same properties... then you shouldn't search the resultant json for your data.
Rather then, you need to create your own data structure against which you will be able to search/index and then loop through your json, parsing each level within to decide how to map that particular element to your new data structure.
Here's an example of what you might could do...
var exampleResults1 = {
"results": [{
"group": {
"queueId": "someID"
},
"data": [{
"metric": "oOnQueueUsers",
"qualifier": "INTERACTING",
"stats": {
"count": 2
}
},
{
"metric": "oOnQueueUsers",
"qualifier": "IDLE",
"stats": {
"count": 5
}
}
]
},
{
"group": {
"queueId": "someID",
"mediaType": "voice"
},
"data": [{
"metric": "oWaiting",
"stats": {
"count": 0
}
}]
}
]
}
var newDataSource = {
parseResults: function(resultObj) {
resultObj.results.forEach(function(result) {
var queueID = result.group.queueId;
if (!newDataSource.hasOwnProperty(queueID)) {
newDataSource[queueID] = {
data: {}
};
}
var newDataSourceQueue = newDataSource[queueID];
result.data.forEach(function(dataObj) {
var metric = dataObj.metric;
if (!newDataSourceQueue.data.hasOwnProperty(metric)) {
newDataSourceQueue.data[metric] = {};
}
var queueMetric = newDataSourceQueue.data[metric];
var qualifier = "noQualifier";
if (dataObj.hasOwnProperty("qualifier")) {
qualifier = dataObj.qualifier;
}
queueMetric[qualifier] = {};
var metricQualifier = queueMetric[qualifier];
var statKeys = Object.keys(dataObj.stats);
statKeys.forEach(function(stat) {
if (!metricQualifier.hasOwnProperty(stat)) {
metricQualifier[stat] = dataObj.stats[stat];
}
});
});
});
}
};
newDataSource.parseResults(exampleResults1);
console.log(JSON.stringify(newDataSource));
console.log("IDLE Count = " + newDataSource["someID"]["data"]["oOnQueueUsers"]["IDLE"]["count"]);
Running this code, you should be able to see what the new data structure looks like after its been populated with values from your original json object. Notice how the keys of the objects are values from the original json.
My example code here doesn't take into account all data points in your example result sets... but should be enough to illustrate that you need to understand the data you are getting back and be able to come up with a consolidated data structure to encapsulate it using property keys that come from the actual returned results.

filter object by two nested values

I'm facing a problem with filter method. On my page there's an input to search matches by team names. Filter value is being stored to React state. Matches object looks like this:
[
{
"id": 4,
"teamBlue": {
"id": 36,
"name": "nameForTeamBlue",
"playerList": [
{
[...]
}
]
},
"teamRed": {
"id": 37,
"name": "nameForTeamRed",
"playerList": [
{
[...]
}
]
},
"localDate": "2020-01-01",
"localTime": "00:00:00",
"referee": null,
"commentator1": null,
"commentator2": null,
"streamer": null,
"stage": {
"id": 2,
"name": "GROUPSTAGE"
},
"onLive": true,
"finished": false
},
]
I tried tons of methods to filter matches by team name, for example:
let criteria = {
teamBlue: {
name: this.state.filter
},
teamRed: {
name: this.state.filter
}
};
let filteredMatches = this.state.matches.filter(function(item) {
for (let key in criteria) {
if (item[key] === undefined || item[key] !== criteria[key])
return false;
}
return true;
});
console.log(filteredMatches);
but none of them worked.
Is there any way to filter these matches so when I type "blue" into my input, it will show all matches where team name contains "blue"?
Thanks in advance!
Try updating the condition to:
if (!item[key] || item[key].name !== criteria[key].name)
let filteredMatches = this.state.matches.filter(function(item) {
let flag = true;
for (let key in criteria) {
// update this to
if (!item[key] || item[key].name !== criteria[key].name)
flag = false;
}
return flag;
});
The name property is missing :
if (key in item && item[key].name !== criteria[key].name)
You're comparing objects with === which will return false. You either need to use a deep comparison method from a library, or implement it yourself like below:
const matches = [ {"id": 4,
"teamBlue": {
"id": 36,
"name": "nameForTeamBlue",
"playerList": []
},
"teamRed": {
"id": 37,
"name": "nameForTeamRed",
"playerList": []
},
}, {"id": 4,
"teamBlue": {
"id": 36,
"name": "nameForTeamBlue",
"playerList": []
},
"teamRed": {
"id": 37,
"name": "nameForTeamRead",
"playerList": []
},
}]
const criteria = {
teamBlue: {
name: 'nameForTeamBlue',
},
teamRed: {
name: 'nameForTeamRed',
}
}
const filteredMatches = matches.filter((item) => {
const allCriteriaMatched = Object.entries(criteria)
.every(([key, value]) => {
const matched = Object.entries(value).every(([criteriaKey, criteriaValue]) => {
const itemValue = item[key][criteriaKey]
const matched = itemValue == criteriaValue
if (!matched) console.log('Item %s does not matched criteria %s. Item\'s value is %s, but criteria value is %s', item[key]['id'], criteriaKey, itemValue, criteriaValue, criteriaValue)
return matched
})
if (!matched) return false
return true
}, {})
return allCriteriaMatched
})
console.log(filteredMatches);
Basically, you just need to go 1 level deeper :D if your criteria can have multiple nested objects, then there's no point doing it manually. You can try to map criteria to run against matches so that you don't use === on objects, but only primitives.

Get full path of object in deeply nested object in JavaScript [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
My source array looks like this:
arr =[
{
"dimensionId": 1,
"dimensionName": "dimensionName1",
"components": [
{
"componentId": 1,
"componentName": "componentName1",
"indicators": [
{
"indicatorId": 1,
"indicatorName": "indicatorName1"
},
{...}
]
},
{...}
]
},
{...}
];
When I am trying to search the most deeply nested object by 'indicatorId' using .filter and .map , it return the object like this:
{
"indicatorId": 1,
"indicatorName": "indicatorName1"
}
What I need to do is keep track of the parent's properties as well when traversing through it's childrens. Desired output will be like this:
{
"dimensionId": 1,
"dimensionName": "dimensionName1",
"componentId": 1,
"componentName": "componentName2",
"indicatorId": 1,
"indicatorName": "indicatorName3"
}
Is there a way to do this recursively?
Edit: The id's are not unique throughout the array
You can loop through and return when found.
arr =[
{
"dimensionId": 1,
"dimensionName": "dimensionName1",
"components": [
{
"componentId": 2,
"componentName": "componentName2",
"indicators": [
{
"indicatorId": 3,
"indicatorName": "indicatorName3"
},
{
"indicatorId": 3.1,
"indicatorName": "indicatorName31"
},
]
}
]
},
];
let out = {}
arr.forEach(({dimensionId, dimensionName, components}) => {
components.forEach(({indicators, componentId, componentName}) => {
let found = indicators.find(({indicatorId}) => indicatorId === 3);
if (found) {
out = {dimensionId, dimensionName, componentId, componentName, ...found};
return;
}
});
})
console.log(out)
You could add the index to the keys form the same arrays and return a new object for each nested array.
function getFlat(array) {
return array.reduce((r, o, i) => {
Object
.entries(o)
.forEach(([k, v]) => Object.assign(r, Array.isArray(v)
? getFlat(v)
: { [[k, i].join('_')]: v }
));
return r;
}, {});
}
var data = [{ dimensionId: 1, dimensionName: "dimensionName1", components: [{ componentId: 2, componentName: "componentName2", indicators: [{ indicatorId: 3, indicatorName: "indicatorName3" }, { indicatorId: 4, indicatorName: "indicatorName4" }] }, { componentId: 5, componentName: "componentName5", indicators: [{ indicatorId: 6, indicatorName: "indicatorName6" }, { indicatorId: 7, indicatorName: "indicatorName8" }] }] }];
console.log(getFlat(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Create an object from array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to convert the array to map,
The array looks like :
var array = [{
"id" : 123
}, {
"id" : 456
}, {
"id" : 789
}];
The final object I'm trying to build should look like :
var result = {
"123": { id: 123 } ,
"456": { id: 456 } ,
"789": { id: 789 }
};
Any efficient way to implement it will be appreciated :)
Thanks
var array = [
{
"id": 123,
"otherProp": "true"
},
{
"id": 456,
"otherProp": "false"
},
{
"id": 789,
"otherProp": "true"
}
];
var result = array.reduce(function (acc, cur, i) {
acc[cur.id] = cur;
return acc;
}, {});
console.log(result);
Use javaScript reduce
The reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
Use reduce
var array = [{
"id" : 123
}, {
"id" : 456
}, {
"id" : 789
}];
var expectedValue = {
"123": { id: 123 } ,
"456": { id: 456 } ,
"789": { id: 789 }
};
var result = array.reduce( (acc, c) => (acc[ c.id ] = c, acc) ,{});
console.log('result : ', result);
console.log('(JSON.stringify(expectedValue) === JSON.stringify(result)) ? ', (JSON.stringify(expectedValue) === JSON.stringify(result)));
.as-console-wrapper { max-height: 100%!important; top: 0; }
Explanation
Use reduce to iterate and initialize the accumulator to {}
Set the key as id of item of every iteration c and value as c itself.

Trying to nest dynamically generated JSON based on user input in Javascript

I am fairly new at manipulating and writing JSON objects etc and I have this task to dynaimcally create JSON object based on user input. I have managed to create the object at 1 level, but i want to nest objects within objects, this is the desired output
// desired output
masterObj = [
{
"Market1": {
"Size1": {
"id": 1,
"reporting_label": "a",
...
},
"Size2": {
"id": 2,
"reporting_label": "a",
...
},
"Size3": {
"id": 3,
"reporting_label": "a",
...
},
"Size4": {
"id": 4,
"reporting_label": "a",
...
},
"Size5": {
"id": 5,
"reporting_label": "a",
...
}
},
"Market2": {...},
"Market3": {...},
"Market4": {...}
}
]
I am trying to use the push function on my masterObj and then in the for loop push the required objects into the child of the masterObj for each market. But all i can get to is having all objects on the same level (ie 9 objects), having started going round in circles now trying to solve this...
var masterObj = [{
}];
var requested = [
{
"Markets": {
// boolean values defined by checkboxes
"Market1": show_m1, "Market2": show_m2, "Market3": show_m3, "Market4": show_m4
},
"Sizes": {
// boolean values defined by checkboxes
"Size1": show_s1, "Size2": show_s2, "Size3": show_s3, "Size4": show_s4, "Size5": show_s5
}
}
]
for (var item of requested) {
if(item.Markets.Market1 === true ) {
var m1Obj = {Market1: {}}
masterObj.push(m1Obj);
if(item.Sizes.Size1 === true) {
var s1Obj = {
Size1: {}
}
masterObj.push(s1Obj);
}
if(item.Sizes.Size2 === true) {
var s2Obj = {
Size2: {}
}
sgObj.push(s2Obj);
}
if(item.Sizes.Size3 === true) {
var s3Obj = {
Size3: {}
}
sgObj.push(s3Obj);
}
if(item.Sizes.Size4 === true) {
var s4Obj = {
Size4: {}
}
masterObj.push(s4Obj);
}
if(item.Sizes.Size5 === true) {
var s5Obj = {
Size5: {}
}
masterObj.push(s5Obj);
}
}
if(item.Markets.Market2 === true ) {
var m2Obj = {
Market2: {}
}
// ouput each requested size
masterObj.push(m2Obj);
}
if(item.Markets.Market3 === true ) {
var m3Obj = {
Market3: {}
}
// ouput each requested size
masterObj.push(m3Obj);
}
if(item.Markets.Market4 === true ) {
var m4Obj = {
Market4: {}
}
// ouput each requested size
masterObj.push(m4Obj);
}
}
console.log(masterObj);
Any help with this would be amazing, In my head i believe I am close to the solution but at the moment its evading me!
Push won't work because your object has an array of one element.. which is an object not an array
masterObj = [ { ... } ]
More than likely you mean to have this kind of a construct:
masterObj = {
"Market1": {
"Size1": {
"id": 1,
"reporting_label": "a",
...
},
"Size2": {
"id": 2,
"reporting_label": "a",
...
},
"Size3": {
"id": 3,
"reporting_label": "a",
...
},
"Size4": {
"id": 4,
"reporting_label": "a",
...
},
"Size5": {
"id": 5,
"reporting_label": "a",
...
}
},
"Market2": {...},
"Market3": {...},
"Market4": {...}
}
which you can then access with
masterObj.Market7 = {...};
Or, if you need to access through a variable:
key = 'Market7';
masterObj[key] = {...};
EDIT: Note: JSONS has nothing to do with this question. You are dealing with straight objects and arrays. JSON applies only when you serialize/deserialize this object into a string -- usually for storage or transport.
With a little restructuring this is the code i have ended up with and I am now getting what i needed.
thanks Jeremy for pointing me in the right direction.
var requestedMarkets = [
{market: "Market1", display: show_m1, name: "m1"},
{market: "Market2", display: show_m2, name: "m2"},
{market: "Market3", display: show_m3, name: "m3"},
{market: "Market4", display: show_m4, name: "m4"}
];
var requestedSizes = [
{display: show_s1, size: '100x200', name: "S1"},
{display: show_s2, size: '100x300', name: "S2"},
{display: show_s3, size: '100x400', name: "S3"},
{display: show_s4, size: '100x500', name: "S4"},
{display: show_s5, size: '100x600', name: "S5"}
];
for (let item of requestedMarkets) {
if(item.display === true ) {
masterObj[item.market] = {};
for (let size of requestedSizes) {
var settings = {
id: uniqueID,
...
}
if(size.display === true) {
masterObj[item.market][size.name] = settings;
}
}
}
}
console.log(masterObj);

Categories

Resources