Related
I get some records from a database in the following JSON format:
data: [{
"y": "0.652008685",
"x": "-0.13926217",
"geneName": "ADAMTS2",
"cond": "Cell"
},
{
"y": "-3.486001",
"x": "-2.295312",
"geneName": "IGSF22",
"cond": "ECM"
},
{
"y": "-3.597706",
"x": "-2.672138",
"geneName": "OXA1L",
"cond": "ECM"
}
]
I would like to transform the above result and group the y,x and geneName name/value pairs based on the cond key using JavaScript.
The result I'd like is shown below:
series: [{
name: 'Cell',
color: '#fff',
data: [{
"name": "ADAMTS2",
"x": -0.13926217,
"y": 0.652008685
}]
},
{
name: 'ECM',
color: '#000',
data: [{
"name": "IGSF22",
"x": -2.295312,
"y": -3.486001
},
{
"name": "OXA1L",
"x": -2.672138,
"y": -3.597706
}
]
}
]
For every different grouping I'd like to add an extra name/value pair color.
Is there any smart and quick way to do it using JavaScript by avoiding the naive approach of the for loops?
Thanks in advance
You could use Array.prototype.reduce to group common objects by object.cond, like so:
var data = [{
"y": "0.652008685",
"x": "-0.13926217",
"geneName": "ADAMTS2",
"cond": "Cell"
},
{
"y": "-3.486001",
"x": "-2.295312",
"geneName": "IGSF22",
"cond": "ECM"
},
{
"y": "-3.597706",
"x": "-2.672138",
"geneName": "OXA1L",
"cond": "ECM"
}
];
var dataMap = data.reduce((result, item) => {
// create root-level object for a name if it doesn't already exist
if (!result[item.cond]) {
result[item.cond] = {
name: item.cond,
color: ''/*not sure what your logic is here*/,
data: []
}
}
// add current item to the root-level object data
result[item.cond].data.push({
name: item.geneName,
x: parseFloat(item.x),
y: parseFloat(item.y)
});
return result;
}, {/*resulting map*/});
// last step is to get an array of the values since that's the desired format
data = Object.values(dataMap);
document.getElementById('result').innerHTML = JSON.stringify(data, null, 4);
<pre id="result"></pre>
You can use .reduce here. Make a object whose key is basically cond and then from that object transform a array using .map.
var x = {
data: [{
"y": "0.652008685",
"x": "-0.13926217",
"geneName": "ADAMTS2",
"cond": "Cell"
},
{
"y": "-3.486001",
"x": "-2.295312",
"geneName": "IGSF22",
"cond": "ECM"
},
{
"y": "-3.597706",
"x": "-2.672138",
"geneName": "OXA1L",
"cond": "ECM"
}
]
};
x.data = Object.entries(x.data.reduce((acc, el) => {
let cond = el.cond;
delete el.cond;
if(acc.hasOwnProperty(cond)){
acc[cond].data.push(el);
}
else{
acc[cond] = {};
acc[cond].data = [el];
}
return acc;
}, {})).map(el => {
return {name: el[0], data: el[1].data};
});
console.log(x);
data = [{
"y": "0.652008685",
"x": "-0.13926217",
"geneName": "ADAMTS2",
"cond": "Cell"
},
{
"y": "-3.486001",
"x": "-2.295312",
"geneName": "IGSF22",
"cond": "ECM"
},
{
"y": "-3.597706",
"x": "-2.672138",
"geneName": "OXA1L",
"cond": "ECM"
}
]
series = []
definedName = []
data.forEach(function(item) {
var ind = definedName.findIndex((element) => {
return element == item.cond;
});
if (ind === -1) {
obj = {
name: item.cond,
color: '#fff',
data: [{
"name": item.geneName,
"x": item.x,
"y": item.y
}]
}
definedName.push(item.cond)
series.push(obj)
} else {
obj = {
"name": item.geneName,
"x": item.x,
"y": item.y
}
series[ind]["data"].push(obj)
}
});
console.log(series)
I have a 2D array of x and y coordinates in Javascript, where the array looks like this:
---> 0: 0 1 .....
{x:1, y:1}, {x:1, y:2} .....
---> 1: 0 1 .....
{x:1, y:1}, {x:1, y:2} .....
So if I for instance write Array[0][0].x, the output is 1.
I would like to turn this array into a JSON string, which would have the following syntax:
{
"name0": [
{
"0": [
{
"x": "1",
"y": "1"
},
{
"x": "1",
"y": "2"
}
],
"1": [
{
"x": "1",
"y": "2"
},
{
"x": "2",
"y": "1"
}
]
}
],
"name1": [
{
"0": [
{
"x": "1",
"y": "1"
},
{
"x": "1",
"y": "2"
}
],
"1": [
{
"x": "1",
"y": "2"
},
{
"x": "2",
"y": "1"
}
]
}
]
}
where name0 and name1 (nameX) are not inside the mentioned 2d array, but passed from somewhere else inside the function where I am creating the JSON. Also, each nameX object is supposed to be pushed into the JSON with the call of this function.
var data;
data[name1] = yourDataA;
data[name2] = yourDataB;
json = JSON.parse(data);
Just prepare your data var the way you need it.
use https://github.com/douglascrockford/JSON-js library, just include the code and use the JSON.stringify() method for converting your array.
I'm using Underscore.js to map a new object array out of an existing object array but cannot really get the desired results.
Essentially I have an object array like:
[
{
"total": 5.21,
"number": 3,
"a": "Paid",
"y": 2015,
"m": 1,
"d": "2015-01-17T23:58:34.115Z"
},
{
"total": 374.65,
"number": 3,
"a": "Scheduled",
"y": 2015,
"m": 1,
"d": "2015-01-18T02:16:03.503Z"
},
{
"total": 310.84,
"number": 1,
"a": "Paid",
"y": 2015,
"m": 1,
"d": "2015-01-17T23:58:34.115Z"
},
{
"total": 284.41,
"number": 3,
"a": "Scheduled",
"y": 2015,
"m": 1,
"d": "2015-01-18T02:16:03.503Z"
}
]
which I would like to map into something like:
[
{
"key": "Paid",
"values": [
[
"2015-01-17T23:58:34.115Z",
5.21
],
[
"2015-01-17T23:58:34.115Z",
310.84
]
]
},
{
"key": "Scheduled",
"values": [
[
"2015-01-18T02:16:03.503Z",
374.65
],
[
"2015-01-18T02:16:03.503Z",
284.41
]
]
}
]
I've tried using the ._map method returns a map like this (JSFiddle):
var mapped_bill = _.map(bill, function(item) {
return {"key": item.a, "values": [item.d, item.total]}
});
console.log(JSON.stringify(mapped_bill));
/* returns:
[
{
"key": "Paid",
"values": [
"2015-01-17T23:58:34.115Z",
5.21
]
},
{
"key": "Scheduled",
"values": [
"2015-01-18T02:16:03.503Z",
374.65
]
},
{
"key": "Paid",
"values": [
"2015-01-17T23:58:34.115Z",
310.84
]
},
{
"key": "Scheduled",
"values": [
"2015-01-18T02:16:03.503Z",
284.41
]
}
]
*/
How do I group the resulting map above so that I can achieve the desired map?
You can use two _.map methods with _.groupBy:
var result = _.map(_.groupBy(data, 'a'), function(el, key) {
return {
key: key,
values: _.map(el, function(item) {
return [item.d, item.total];
})
};
});
Check the demo below.
var data = [
{
"total": 5.21,
"number": 3,
"a": "Paid",
"y": 2015,
"m": 1,
"d": "2015-01-17T23:58:34.115Z"
},
{
"total": 374.65,
"number": 3,
"a": "Scheduled",
"y": 2015,
"m": 1,
"d": "2015-01-18T02:16:03.503Z"
},
{
"total": 310.84,
"number": 1,
"a": "Paid",
"y": 2015,
"m": 1,
"d": "2015-01-17T23:58:34.115Z"
},
{
"total": 284.41,
"number": 3,
"a": "Scheduled",
"y": 2015,
"m": 1,
"d": "2015-01-18T02:16:03.503Z"
}
];
var result = _.map(_.groupBy(data, 'a'), function(el, key) {
return {
key: key,
values: _.map(el, function(item) {
return [item.d, item.total];
})
};
});
pre.innerHTML = JSON.stringify(result, null, 4);
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<pre id="pre"></pre>
Going by your history here then it could be assumed this is actually a mongodb question even though you are just looking at the resulting JavaScript object in the question as presented.
So with the structure you mention actually being the members of a MongoDB collection then the answer to produce the the required output would be:
db.mapped.aggregate([
{ "$group": {
"_id": "$a",
"values": {
"$push": {
"$map": {
"input": { "$literal": ["A","B"] },
"as": "l",
"in": {
"$cond": [
{ "$eq": [ "$$l", "A" ] },
"$d",
"$total"
]
}
}
}
}
}}
])
So the $map operator there processes our "two element array template" provided in the $literal operator section, and "transposes" the values via the $cond "ternary" to either produce the element from "$d" where the first "A" element is matched or the element "$total" where the element is not "A" but therefore "B" as the only other logical choice.
Results in mapping an array that has the first elementof the first match and the second element as the other expected value. These can then be provided to $push, to create and "array of arrays" as requested.
Which produces from your source as a collection:
{
"_id" : "Scheduled",
"values" : [
[
"2015-01-18T02:16:03.503Z",
374.65
],
[
"2015-01-18T02:16:03.503Z",
284.41
]
]
},
{
"_id" : "Paid",
"values" : [
[
"2015-01-17T23:58:34.115Z",
5.21
],
[
"2015-01-17T23:58:34.115Z",
310.84
]
]
}
So you didn't need this post processing in JavaScript as you thought you did. Using the operators that are appropriate to match your conditions on the server side $group is all you need.
I have a JSON like the following, I am trying to remove "age" from it and rename "name" to "key" and "height" to "value". Can someone please suggest what would be the neatest way to achieve this.
{
"data": [
{
"name": "A",
"age": 8,
"height": 120
},
{
"name": "B",
"age": 18,
"height": 150
}
]
}
Here is how you do it using map as I mentioned.
map is exactly what you're looking for, it's a way to create a new array based on an existing array using whatever criteria you want.
var json = {
"data": [{
"name": "A",
"age": 8,
"height": 120
}, {
"name": "B",
"age": 18,
"height": 150
}]
};
json.data = json.data.map(function (d) {
return {
key: d.name,
value: d.height
};
});
How I can add 3 lines to the graphic in xCharts? For make graphic with 2 lines I should write:
var data = {
"xScale": "time",
"yScale": "linear",
"type": "line",
"main": [
{
"data": getStatistic(), // Some JSON data
},
],
"comp": [
{
"type": "line",
"data": getStatistic(), // Some JSON data
},
],
};
But adding one more "comp" element doesn't work. On library website I not found graphic with more than two lines...
The answer can be found here: https://github.com/tenXer/xcharts/issues/21
main data and comp are data both Arrays. They can take many different data sets. The documentation might not explain this very well...
You can provide multiple data sets to the main Array to accomplish what you'd like. In example, here is how you might draw both pizza and tacos:
{
"main": [
{
"className": ".pizza",
"data": [
{
"x": "2012-11-05",
"y": 12
},
{
"x": "2012-11-06",
"y": 8
}
]
},
{
"className": ".tacos",
"data": [
{
"x": "2012-11-05",
"y": 8
},
{
"x": "2012-11-06",
"y": 11
}
]
}
]
}
You can add more data sets to this main Array. There is no limit.