Create a map out of a grouped array objects - javascript

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.

Related

Read Google Sheet Exported JSON by column name in Apps Script

I'm exploring the use of JSON exported Google Sheets as database for Apps Script.
The fetched url follows the structure:
https://docs.google.com/spreadsheets/d/DOCUMENTID/gviz/tq?tqx=out:json&gid=SHEETID
JSON.json
{
"reqId": "0",
"sig": "000",
"status": "ok",
"table": {
"cols": [
{
"id": "A",
"label": "",
"type": "string"
},
{
"id": "B",
"label": "",
"type": "string"
},
{
"id": "C",
"label": "",
"type": "string"
}
],
"parsedNumHeaders": 0,
"rows": [
{
"c": [
{
"v": "Data 1-1"
},
{
"v": "Data 1-2"
},
{
"v": "Data 1-3"
}
]
},
{
"c": [
{
"v": "Data 2-1"
},
{
"v": "Data 2-2"
},
{
"v": "Data 2-3"
}
]
},
{
"c": [
{
"v": "Emails"
},
{
"v": "Ids"
},
{
"v": "Names"
}
]
}
]
},
"version": "0.6"
}
In this function I'm getting returned an array of values for the C column:
dataArray = [Data 1-3, Data 2-3]
function getRolePermission(databaseUrl) {
let databaseParsed = JSON.parse(UrlFetchApp.fetch(databaseUrl).getContentText().match(/(?<=.*\().*(?=\);)/s)[0]);
let tableLength = Object.keys(databaseParsed.table.rows).length;
let dataArray = [];
for (let i = 0; i < tableLength; i++) {
dataArray.push(databaseParsed.table.rows[i].c[2].v)
}
return dataArray;
}
It works well, but I don't know how to make this function more generic, so I call it with (url, headerName) arguments to get an array with the values of a column. Something like:
function getRolePermission(databaseUrl, headerName) {
// CODE ??
return dataArray;
}
getRolePermission('https://docs.google.com/spreadsheets/d/1lc...', 'Emails')
to get dataArray = [Data 1-3, Data 2-3], so if I change the order of columns I'm still getting the same results.
dataArray.push(databaseParsed.table.rows[i].c[2].v)
You just need to find the index 2 here to make the function more generic. The table.cols should give you the column headers, but it is not doing that because parsedNumHeaders is 0 in your case. To manually set number of headers, use &headers=1. The url should look like:
https://docs.google.com/spreadsheets/d/DOCUMENTID/gviz/tq?tqx=out:json&gid=SHEETID&headers=1
The response then would look like:
{
"reqId": "0",
"sig": "000",
"status": "ok",
"table": {
"cols": [
{
"id": "A",
"label": "Names",
"type": "string"
},
{
"id": "B",
"label": "Ids",
"type": "string"
},
{
"id": "C",
"label": "Emails",
"type": "string"
}
],
"parsedNumHeaders": 1,
"rows": [
{
"c": [
{
"v": "Data 1-1"
},
{
"v": "Data 1-2"
},
{
"v": "Data 1-3"
}
]
},
{
"c": [
{
"v": "Data 2-1"
},
{
"v": "Data 2-2"
},
{
"v": "Data 2-3"
}
]
}
]
},
"version": "0.6"
}
Once you get the headers, you can find the index:
const columnNeeded = databaseParsed.table.cols.findIndex(obj => obj.label === headerName/*"Emails"*/);
Then, use it in your function
dataArray.push(databaseParsed.table.rows[i].c[columnNeeded].v)

How do I access data in a nested json with lists?

This has been a real pain for me and I can't solve it. I have a Json that looks like this:
"name": "The data",
"list": [
{
"item": "a613424",
"locations": [
{
"name": "start",
"a": 5.743,
"b": 0.093
}
]
},
{
"item": "e88934",
"locations": [
{
"name": "start",
"a": 6.64,
"b": 0.43
}
]
},
{
"item": "d92213",
"locations": [
{
"name": "start",
"a": 12.33,
"b": 0.91
},
{
"name": "stop",
"a": 889,
"b": 1.134
}
]
}]}
Every item has an item code, and in locations has a name and values for a and b. Some items have 2 names. I need to read through this and extract the item code, name(s) and a and b values. I don't know how many items will be in the json or which items will have multiple names.
I either get an object returned or 'unknown'
x = test_data.list[0]; document.write(x);
outputs [object object]
document.write(test_data[0]);
outputs 'undefined'
I could do this in 5 minutes in Python, but sadly this has to be in javascript.
Thanks
Access the lists through forEach and item and locations properties. It's easy since you have a constant structure for your JSON
let data = {
"name": "The data",
"list": [{
"item": "a613424",
"locations": [{
"name": "start",
"a": 5.743,
"b": 0.093
}]
},
{
"item": "e88934",
"locations": [{
"name": "start",
"a": 6.64,
"b": 0.43
}]
},
{
"item": "d92213",
"locations": [{
"name": "start",
"a": 12.33,
"b": 0.91
},
{
"name": "stop",
"a": 889,
"b": 1.134
}
]
}
]
};
let listItems = data.list;
listItems.forEach(item => {
console.log("item code: " + item.item); // item code
item.locations.forEach(location => {
console.log("location a is: " + location.a); // a
console.log("location b is: " + location.b); // b
});
console.log("\n"); //for breakline
});
let objectData = {
name: "The data",
list: [
{
item: "a613424",
locations: [
{
name: "start",
a: 5.743,
b: 0.093
}
]
},
{
item: "e88934",
locations: [
{
name: "start",
a: 6.64,
b: 0.43
}
]
},
{
item: "d92213",
locations: [
{
name: "start",
a: 12.33,
b: 0.91
},
{
name: "stop",
a: 889,
b: 1.134
}
]
}
]
};
let obDList = objectData.list.map((x) =>
x.locations.map((y) => {
return `a = ${y.a}, b = ${y.b} `;
})
);
console.log(obDList);
console.log(obDList[2][1]);

How to groupBy in multi arrays using lodash

I want to group By sub-work in array
Here is my array I want to group By sub-work
result = [
{
"date": "10-07-2019",
"data": [
{
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [
{
"id": 7,
"title": 'subdata-1',
}
]
}
]
},
{
"date": "12-07-2019",
"data": [
{
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [
{
"id": 7,
"title": 'subdata-1',
}
]
}
]
},
]
Here is what I try
result = _(result)
.map(function(items, data) {
_.groupBy(items.data, function({ sub_work }) {
return sub_work;
});
})
.value();
first I map result into data then I try to groupby but It's return null
Update
I want my output look like this
[
{
"date": "10-07-2019",
sub-work: [{
sub-work : "sub_work1",
sub-data[
{
"id": 7,
"title": 'subdata-1',
}
]
}]
}
]
...........................
It would be better if you could provide your expected result.
Here's what I could infer:
_(result)
.map(function(obj) { // Convert into a 2D array.
return obj.data.map(e => Object.assign(e, {date: obj.date}));
})
.flatten() // We have an array of objects now.
.groupBy('sub-work') // We can call groupBy().
.value();
Here's what you get:
{
"sub_work1": [{
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [{
"id": 7,
"title": "subdata-1"
}],
"date": "10-07-2019"
}, {
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [{
"id": 7,
"title": "subdata-1"
}],
"date": "12-07-2019"
}]
}

Object version of mapping

Duplicate of: map function for objects (instead of arrays)
How do i map or iterate through an object where the values is another object as such:
[{
"id":2,
"name":"Jane Smith",
"position":"Cook",
"applied":"02/08/16",
"experience":4,
"availability":{
"M":1,
"T":1,
"W":1,
"Th":1,
"F":0,
"S":0,
"Su":0
},
"questions": [{
"text":"Have you ever been convicted of a felony?",
"answer":"Yes"
}]
},
...(2 other objects with the same format)....
]
I need to access the availability object
Beware that there is no guarantee of the order of an object's keys, so there is no perfectly consistent way to iterate over them. However, you can use the for...in statement to iterate over the enumerable properties of an object. You can use that to basically iterate through they key/value pairs of an objects and do something with them.
const availability = {
"M":1,
"T":1,
"W":1,
"Th":1,
"F":0,
"S":0,
"Su":0
};
for (const key in availability) {
console.log(key, availability[key]);
}
// Output:
/*
M 1
T 1
W 1
Th 1
F 0
S 0
Su 0
*/
Since it is unclear exactly how you want to use the data I can't provide any more detail than that but it should get you started.
The map() equivalent of object is Object.keys() and Object.entries()
It is a feature introduced in ES7
const data = [{
"id":2,
"name":"Jane Smith",
"position":"Cook",
"applied":"02/08/16",
"experience":4,
"availability":{
"M":1,
"T":1,
"W":1,
"Th":1,
"F":0,
"S":0,
"Su":0
},
"questions": [{
"text":"Have you ever been convicted of a felony?",
"answer":"Yes"
}]
}
]
console.log(Object.entries(data[0].availability));
console.log(Object.keys(data[0].availability));
Check this here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
For your data if you have more than one object then you can first iterate through the array first using array.map() and use Object.entries() inside map()
I assume you want a list of availability objects.
const availabilityObjects = objects.map(object => object.availability)
Will do it. Code snippet follows:
const objects = [{
"id": 2,
"name": "Jane Smith",
"position": "Cook",
"applied": "02/08/16",
"experience": 4,
"availability": {
"M": 1,
"T": 1,
"W": 1,
"Th": 1,
"F": 0,
"S": 0,
"Su": 0
},
"questions": [{
"text": "Have you ever been convicted of a felony?",
"answer": "Yes"
}]
},
{
"id": 2,
"name": "Jane Smith",
"position": "Cook",
"applied": "02/08/16",
"experience": 4,
"availability": {
"M": 1,
"T": 1,
"W": 1,
"Th": 1,
"F": 0,
"S": 0,
"Su": 0
},
"questions": [{
"text": "Have you ever been convicted of a felony?",
"answer": "Yes"
}]
},
{
"id": 2,
"name": "Jane Smith",
"position": "Cook",
"applied": "02/08/16",
"experience": 4,
"availability": {
"M": 1,
"T": 1,
"W": 1,
"Th": 1,
"F": 0,
"S": 0,
"Su": 0
},
"questions": [{
"text": "Have you ever been convicted of a felony?",
"answer": "Yes"
}]
}
]
console.log(objects.map(object => object.availability))

JSON format for Google chart stacked column

I have data like below:
store 1 Store 2
store_id walk-ins walk-ins
morning 20 25
noon 35 40
night 50 55
There are 20 stores to chart stacking the values of each row.
Google Charts docs tells me the data array looks like this:
var data = google.visualization.arrayToDataTable([
['Stores', 'Store 1', 'Store 2', 'Store 3', 'Store 4', ... ],
['morning', 10, 24, 20, 32, 18, 5, ...],
['noon', 16, 22, 23, 30, 16, 9, ...],
['night', 28, 19, 29, 30, 12, 13, ...],
]);
I am getting the data via MySQL script / server PHP script. What should the JSON look like? The json_encode($data) from MySQL query returns as follows;
[{"store_name":"Store 1","Time":"Morning","count":"17"}, ...]
but the chart does not load and gives me a message "Table has no columns".
I load JSON as follows:
var url = '/url/updatedata.php?var=querytype';
jQuery.getJSON( url, function(Json) {
// Create and populate the data table.
var data = new google.visualization.DataTable(Json);
....
What is the structure of the JSON for a stacked column chart?
Thanks!
I know this is an old post, but in case if any one needs it, here is the format for Jsondata for using google's stacked column from server code.
{
"cols": [
{
"id": "",
"label": "title",
"pattern": "",
"type": "string"
},
{
"id": "",
"label": "A",
"pattern": "",
"type": "number"
},
{
"type": "string",
"role": "annotation",
"p": {
"role": "annotation"
}
},
{
"id": "",
"label": "B",
"pattern": "",
"type": "number"
},
{
"type": "string",
"role": "annotation",
"p": {
"role": "annotation"
}
},
{
"id": "",
"label": "C",
"pattern": "",
"type": "number"
},
{
"type": "string",
"role": "annotation",
"p": {
"role": "annotation"
}
},
{
"id": "",
"label": "D",
"pattern": "",
"type": "number"
},
{
"type": "string",
"role": "annotation",
"p": {
"role": "annotation"
}
}
],
"rows": [
{
"c": [
{
"v": "Categories",
"f": null
},
{
"v": "10",
"f": null
},
{
"v": "10",
"f": null
},
{
"v": "20",
"f": null
},
{
"v": "20",
"f": null
},
{
"v": "30",
"f": null
},
{
"v": "30",
"f": null
},
{
"v": "50",
"f": null
},
{
"v": "50",
"f": null
}
]
}
]
}
It turned out that mapping of your data happened to be a quite complex task.
For example, you have this json data:
var json = [
{"store_name":"Store 1","Time":"Morning","count":"10"},
{"store_name":"Store 1","Time":"Noon","count":"16"},
{"store_name":"Store 1","Time":"Night","count":"28"},
{"store_name":"Store 2","Time":"Morning","count":"24"},
{"store_name":"Store 2","Time":"Noon","count":"22"},
{"store_name":"Store 2","Time":"Night","count":"19"}
];
I use underscore.js for the following code. It can be included like this:
<script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
Mapping code:
var header = _.chain(json).pluck("store_name").sort().uniq(true).value();
header.unshift("Stores");
var rows = _.chain(json)
.groupBy(function(item) { return item.Time; })
.map(function(group, key) {
var result = [key];
_.each(group, function(item) {
result[_.indexOf(header, item.store_name)] = parseInt(item.count);
});
return result;
})
.value();
var jsonData = [header].concat(rows);
// draw chart
var data = google.visualization.arrayToDataTable(jsonData);
chart.draw(data, options);
The final jsonData variable looks so:
[["Stores", "Store 1", "Store 2"],
["Morning", 10, 24],
["Noon", 16, 22],
["Night", 28, 19]]
Here is a link to jsFiddle with your chart.

Categories

Resources