Data manipulation in DataTables - javascript

I have a quite complex data manipulation to perform.
My datasource gives me a list of cashflows, grouped by person like that:
{
"months": [
"2016-10-01",
"2016-11-01",
"2016-12-01",
"2017-01-01"
],
"persons": [
{
"label": "John",
"cashflows": [
{
"date": "2016-10-01",
"amount": "1000.00"
},
{
"date": "2016-11-01",
"amount": "1000.00"
}
]
},
{
"label": "Brad",
"cashflows": [
{
"date": "2017-01-01",
"amount": "5540.00"
}
]
}
]
}
I want to put those data in a DataTable, but I don't know how to "JOIN" the months and the cashflows.
My best guest is a sql-like query, but in javascript, in order to perform this pseudo-code:
select each person
for each person
good_row = person.cashflows LEFT JOIN months ON cashflows.date (iiish..)
I have set up a jsfiddle here.

Here is the plain javascript way to do it (the hard way).
Fiddle link: https://jsfiddle.net/ngwqfjo0/
function getDesiredData() {
var persons = real_data["persons"];
var months = real_data["months"];
persons.forEach(function(person) {
var row = [];
var amounts = [];
row.push(person["label"]);
months.forEach(function(month) {
var amount = '';
for(x = 0; x < person["cashflows"].length; x++) {
if(month == person["cashflows"][x]["date"]) {
amount = person["cashflows"][x]["amount"];
break;
}
}
amounts.push(amount);
});
desiredData.push(row.concat(amounts));
});
return desiredData;
}
To make life easier, consider using a functional utility like lodash or underscore
function getDesiredDataEasy() {
var persons = real_data["persons"];
var months = real_data["months"];
var desiredData = [];
return _.map(persons, function(person) {
return _.concat([person["label"]], _.map(months, function(month) {
var cashFlowDate = _.find(person["cashflows"], function(cf) {
return cf.date == month;
});
return cashFlowDate ? cashFlowDate.amount : "";
}));
});
}

Related

Push entire subarray

I have an array this the format below. Trying to push multiple entire subarrays (starting with A-) fulfilling a condition to a new array and keep the array format. Have no success with the code below.
Array:
{"#VER": {
"A-1": {
"verdatum": "2016-07-08",
"vertext": "1073, Almi",
"trans": [{
"account": "1510",
"amount": "52500.00"
}, {
"account": "3010",
"amount": "-42000.00"
}, {
"account": "2611",
"amount": "-10500.00"
}]
},
"A-2": {
"verdatum": "2016-07-08",
"vertext": "1074, Text",
"trans": [{
"account": "1510",
"amount": "15000.00"
}, {
"account": "3010",
"amount": "-12000.00"
}, {
"account": "2611",
"amount": "-3000.00"
}]
}
}
}
Code so far, but changes format of array
var newarray = [];
$.each(array["#VER"], function(i, item) {
if (condition for subarray) {
newarray.push(i,item);
}
});
You're working with an object here, not an array. This code should work:
var data = { ... }; // your original data object
var filteredData = filterData(data);
function filterData(data) {
var verData = data['#VER'];
var filteredVerData = {};
$.each(verData, function(key, value) {
if(value.vertext === '1073, Almi') { // your condition
filteredVerData[key] = value;
}
});
return {
'#VER': filteredVerData
};
}
But if you have many root keys like '#VER' and you need to filter all of them, you'd need to write one more loop:
var data = { ... }; // your original data object
var filteredData = filterData(data);
function filterData(data) {
var result = {};
$.each(data, function(verKey, verData) {
$.each(verData, function(aKey, aData) {
if(aData.vertext === '1073, Almi') { // your condition
result[verKey] = result[verKey] || {};
result[verKey][aKey] = aData;
}
});
});
return result;
}

Push Unique Objects to JavaScript Array

How do I push an object into an specified array that only updates that array? My code pushes an object and updates all arrays, not just the specified one.
Here is the structure of the data:
{
"d": {
"results": [
{
"Id": 1,
"cost": "3",
"item": "Project 1",
"fiscalyear": "2014",
"reportmonth": "July"
}
]
}
}
Here is a sample of the desired, wanted results:
{
"Project 1": [
{
"date": "31-Jul-14",
"rating": "3"
},
{
"date": "31-Aug-14",
"rating": "4"
}
],
"Project 2": [
{
"date": "31-Jul-14",
"rating": "2"
}
]
}
This is my attempt:
var results = data.d.results;
var date;
var projectObj = {},
projectValues = {},
project = '';
var cost = '',
costStatus = '';
for (var i = 0, m = results.length; i < m; ++i) {
project = results[i]['item'];
if (!projectObj.hasOwnProperty(project)) {
projectObj[project] = [];
}
// use Moment to get and format date
date = moment(new Date(results[i]['reportmonth'] + ' 1,' + results[i]['fiscalyear'])).endOf('month').format('DD-MMM-YYYY');
// get cost for each unique project
costStatus = results[i]['cost'];
if (costStatus == null || costStatus == 'N/A') {
cost = 'N/A';
}
else {
cost = costStatus;
}
projectValues['rating'] = cost;
projectValues['date'] = date;
projectObj[project].push(projectValues);
}
Here is a Fiddle with the undesired, unwanted results:
https://jsfiddle.net/yh2134jn/4/
What am I doing wrong?
That is because You do not empty it new iteration. Try this:
for (var i = 0, m = results.length; i < m; ++i) {
projectValues = {};
project = results[i]['item'];
....
}

Ordering recursive function results in arrays of arrays

I am currently dealing with in issue in writing a recrusive function to order some json data. I have several nested arrays of objects which i need to order into single slides. The structure is similar to the following :
[
{
"title": "a",
"children": [
{
"title": "a-a",
"children": [
{
"title": "a-a-a"
},
{
"title": "a-a-b"
}
]
},
{
"title": "a-b",
"children": [
{
"title": "a-b-a"
},
{
"title": "a-b-b"
}
]
}
]
},
{
"title": "b",
"children": [
{
"title": "b-a",
"children": [
{
"title": "b-a-a"
},
{
"title": "b-a-b"
}
]
},
{
"title": "b-b",
"children": [
{
"title": "b-b-a"
},
{
"title": "b-b-b"
}
]
}
]
}
]
I have written a recursive function :
var catalog = {
init: function() {
var _this = this;
$.getJSON("catalog.json", function(data) {
_this.slides = [];
_this.parseCategories(data.catalog.category,-1,0);
});
},
parseCategories: function(array, depth, prevParent) {
++depth;
if (!this.slides[depth]) this.slides[depth] = [];
if (!this.slides[depth][prevParent]) this.slides[depth][prevParent] = [];
this.slides[depth][prevParent].push(array);
for (var i = 0; i < array.length; i++) {
if (array[i].category) {
this.parseCategories(array[i].category, depth, i);
}
}
}
}
catalog.init();
This outputs :
However instead of retrieving the data for my third slide under format :
a-a-a
a-b-a
a-c-a
I would like to get
a-a-[a,b,c]
I was wondering if that was possible since I'm not very good at handling recursive processes. I hope I was clear and thank you for reading this.
I basically need to keep my original data structure but remove the first depth level for each iteration (slide in a slider that represent increasing depths in my data structure).
I recently wrote a algorithm to recursively handle data like this. Here is a jsfiddle and the main function
console.log('starting');
// data in tree format.
var output = {};
// data in slide format ["a-a-a", "a-a-b", "b-b-a", "b-b-b"]
var outputStrs = [];
parseData(data, output);
console.log(output);
console.log(outputStrs);
function parseData(data, store) {
// go through each element
for (var i = 0; i < data.length; i++) {
var element = data[i];
// used to keep track of where we are in the tree.
var splitElement = element.title.split('-');
var titleStart = splitElement[0];
// console.log(element);
if (_.has(element, 'children') && _.isArray(element.children)) {
// if there is a children, then recursively handle it.
store[titleStart] = {};
parseData(element.children, store[titleStart]);
} else {
// if we are at the end, then add in the data differently.
var titleEnd = splitElement[splitElement.length-1];
store[titleEnd] = titleEnd;
// create the slides
var slide = [];
for (var j = 0; j < splitElement.length; j++) {
if (j !== splitElement.length - 1) {
slide.push(titleStart);
} else {
slide.push(titleEnd);
}
}
slide = slide.join('-');
if (!_.contains(outputStrs, slide)) outputStrs.push(slide);
}
}
}
With this data the output should resemble
a
a
a
b
b
b
a
b
And outputStrs will resemble a-a-[a,b,c]
Hope this helps!!!

JSON data transformation from table-like format to JSON?

I have data that's in this format:
{
"columns": [
{
"values": [
{
"data": [
"Project Name",
"Owner",
"Creation Date",
"Completed Tasks"
]
}
]
}
],
"rows": [
{
"values": [
{
"data": [
"My Project 1",
"Franklin",
"7/1/2015",
"387"
]
}
]
},
{
"values": [
{
"data": [
"My Project 2",
"Beth",
"7/12/2015",
"402"
]
}
]
}
]
}
Is there some super short/easy way I can format it like so:
{
"projects": [
{
"projectName": "My Project 1",
"owner": "Franklin",
"creationDate": "7/1/2015",
"completedTasks": "387"
},
{
"projectName": "My Project 2",
"owner": "Beth",
"creationDate": "7/12/2015",
"completedTasks": "402"
}
]
}
I've already got the column name translation code:
r = s.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
}).replace(/[\(\)\s]/g, '');
Before I dive into this with a bunch of forEach loops, I was wondering if there was a super quick way to transform this. I'm open to using libraries such as Underscore.
function translate(str) {
return str.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
})
.replace(/[\(\)\s]/g, '');
}
function newFormat(obj) {
// grab the column names
var colNames = obj.columns[0].values[0].data;
// create a new temporary array
var out = [];
var rows = obj.rows;
// loop over the rows
rows.forEach(function (row) {
var record = row.values[0].data;
// create a new object, loop over the existing array elements
// and add them to the object using the column names as keys
var newRec = {};
for (var i = 0, l = record.length; i < l; i++) {
newRec[translate(colNames[i])] = record[i];
}
// push the new object to the array
out.push(newRec);
});
// return the final object
return { projects: out };
}
DEMO
There is no easy way, and this is really not that complex of an operation, even using for loops. I don't know why you would want to use regex to do this.
I would start with reading out the column values into a numerically indexed array.
So something like:
var sourceData = JSON.parse(yourJSONstring);
var columns = sourceData.columns[0].values[0].data;
Now you have a convenient way to start building your desired object. You can use the columns array created above to provide property key labels in your final object.
var sourceRows = sourceData.rows;
var finalData = {
"projects": []
};
// iterate through rows and write to object
for (i = 0; i < sourceRows.length; i++) {
var sourceRow = sourceRows[i].values.data;
// load data from row in finalData object
for (j = 0; j < sourceRow.length; j++) {
finalData.projects[i][columns[j]] = sourceRow[j];
}
}
That should do the trick for you.

Javascript object group by day,month,year

I am working on application which I need to do grouping of different sets of javascript object and those will be based on month,day and year.
For day I am doing like below
var calculateByDay = function(inputList){
var outPutList = [];
var result = {}
var item = null, key = null;
for(i=0; c<inputList.length; i++) {
item=inputList[c];
key = Object.keys(item)[0];
item=item[key];
if(!result[key]) {
result[key] = item;
}
else {
result[key] += item;
}
for (r in result)
{
var docs = {};
docs["date"] = r;
docs["amount"] = result[r];
outPutList.push(docs);
}
}
return outPutList;
}
How can I improve above code and use it for month and year calculation also?
I went thorough underscore.js and it has a groupBy method. but seems not fits with my requirement.
I want to group by months and year also,
for
var inputList = [{"2012-12-02T00:00": 2000}, {"2013-01-01T00:00": 1200},{"2013-02-02T00:00": 550}, {"2013-02-02T00:00": 1000}];
The output should be:
Monthly :
[{"December 2012": 2000}, {"January 2013": 1200},{"February 2013": 1550}];
Yearly
[{"year 2012": 2000}, {"year 2013": 2750}];
And it seems I need to this kind of map,reduce approach for large data(array sets), is there any other library or practices I can do to make the code solid?
Thanks in advance.
Given a slightly different structure of data:
var data = [{
"date": "2011-12-02T00:00",
"value": 1000
}, {
"date": "2013-03-02T00:00",
"value": 1000
}, {
"date": "2013-03-02T00:00",
"value": 500
}, {
"date": "2012-12-02T00:00",
"value": 200
}, {
"date": "2013-04-02T00:00",
"value": 200
}, {
"date": "2013-04-02T00:00",
"value": 500
}, {
"date": "2013-03-02T00:00",
"value": 500
}, {
"date": "2013-04-12T00:00",
"value": 1000
}, {
"date": "2012-11-02T00:00",
"value": 600
}];
You could use underscore:
var grouped = _.groupBy(data, function(item) {
return item.date;
});
var groupedByYear = _.groupBy(data, function(item) {
return item.date.substring(0,4);
});
var groupedByMonth = _.groupBy(data, function(item) {
return item.date.substring(0,7);
});
console.log(groupedByYear);
See related answer: Javascript - underscorejs map reduce groupby based on date
Please see if the following refactor is useful for you
http://jsfiddle.net/wkUJC/
var dates = [{"2012-12-02T00:00": 2000}, {"2013-01-01T00:00": 1200},{"2013-02-02T00:00": 550}, {"2013-02-02T00:00": 1000}];
function calc(dates) {
var response = {};
dates.forEach(function(d){
for (var k in d) {
var _ = k.split("-");
var year = _[0]
var month = _[1]
if (!response[year]) response[year] = {total: 0}
response[year][month] = response[year][month] ? response[year][month]+d[k] : d[k]
response[year].total+= d[k]
}
});
console.log(response);
return response;
}
calc(dates);

Categories