I have a json document that looks like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"time": 1438342780,
"title": "Iran's foreign minister calls for world's nuclear weapons states to disarm",
"author": "Julian Borger",
"web_id": "world/2015/jul/31/iran-nuclear-weapons-states-disarm-israel"
},
"geometry": {
"type": "Point",
"coordinates": [
-77.26526,
38.90122
]
}
},
{
"type": "Feature",
"properties": {
"time": 1438300867,
"title": "Big bangs over the white cliffs of Dover as unique 1915 artillery gun is fired again",
"author": "Maev Kennedy",
"web_id": "world/2015/jul/31/big-bangs-over-white-cliffs-dover-unique-1915-artillery-gun-fired-again"
},
"geometry": {
"type": "Point",
"coordinates": [
1.3,
51.13333
]
}
}
]
}
I would like to fetch the 'feature' array inside json and return the number of features for a given day. For example, for the data above I would expect something like:
{
"date": 7/31/2015,
"number": 2
}
Currently I have something that looks like this:
d3.json('path/to/json', function(json) {
data = json;
});
Fairly new to js and d3 so a bit stumped. Let me know if you need any more details. Thanks in advance!
This will work for you, it returns an array of object. each object is the object you asked.
var a = yourJSONObject, var map = {}, output = [];
for (var i = 0; i < a.features.length; i++) {
var ref = new Date(a.features[i].properties.time*1000).toDateString();
if (map[ref] == undefined) {
map[ref] = output.push({
date: ref,
number: 1
}) - 1;
} else
output[map[ref]].number++
}
console.log(output) //[ { date: 'Sat Jan 17 1970', number: 2 } ]
The critical piece here is that your time values are in Epoch time, which means you'll have to convert them to preset dates using this technique.
Then you can traverse the features array, and track the count for each date.
var features = yourJSONObject.features;
var featuresByDate = {};
for (var i = 0, len = features.length; i < len; i++) {
// find the current feature's date
var epochTime = features[0].properties.time;
var date = new Date(0);
date.setUTCSeconds(epochTime);
// find the date in 7/31/2015 format
var dateStr = (date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear();
// count the date for the first time if it has not been counted yet
if ( ! featuresByDate.hasOwnProperty(dateStr) ) {
featuresByDate[dateStr] = 1;
}
// otherwise, increment its counter
else {
featuresByDate[dateStr]++;
}
}
Two functions - one to get the correct date based on the epoch time, the other to iterate through the features building a temporary object, then iterating through the object to give you an array of date/number objects.
function getDate(time) {
var d = new Date(0);
d.setUTCSeconds(time);
return [d.getMonth() + 1, d.getDate(), d.getFullYear()].join('/');
}
function getData(data) {
var obj = data.features.reduce(function(p, c) {
var date = getDate(c.properties.time);
p[date] = (p[date] + 1) || 1;
return p;
}, {});
return Object.keys(obj).map(function (el) {
return { date: el, number: obj[el] };
});
}
getData(data);
OUTPUT
[
{
"date": "7/31/2015",
"number": 2
}
]
DEMO
I don't know D3, but you can do this with straight JS:
var json = {
"features": [{
"type": "Feature",
"properties": {
"time": 1438342780,
"title": "Iran's foreign minister calls for world's nuclear weapons states to disarm"
}
}, {
"type": "Feature",
"properties": {
"time": 1438300867,
"title": "Big bangs over the white cliffs of Dover as unique 1915 artillery gun is fired again"
}
}, {
"type": "Feature same date",
"properties": {
"time": 1448300867,
"title": "Big bangs over the white cliffs of Dover as unique 1915 artillery gun is fired again"
}
}]
}
var counts = {}
function secondsToDate(seconds) {
var date = new Date(1970,0,1);
date.setSeconds(seconds);
return date.toDateString();
}
json.features.reduce((counts, feature) => {
var date = secondsToDate(feature.properties.time)
if (counts[date]) {
counts[date]++
} else {
counts[date] = 1
}
return counts
}, counts)
console.log(counts) // {'Fri Jul 31 2015': 2, 'Mon Nov 23 2015': 1}
The missing bit is parsing your timestamp into a date.
Now grouping on dates. Maybe now the downvoter can undo that!
I added an object with a replicated timestamp to highlight the count going up.
Related
I have an array that has a object with two properties, 'location' and 'needs'. The needs property has an array of objects with a date and count {date: "2021-06-15", count: 10} so an array would look like this:
{
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
}
What I need to do is to use Momentjs to use today's date, figure out the two week period starting from today, and then map the needs-count to the date in the moment loop. If there is a date missing (like in the example below), it should put a 0 as the count
A final array would look like...
{
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56 // this had a count in the initial object
},
{
"date": "2021-04-07",
"count": 0
},
{
"date": "2021-04-08",
"count": 0
},
{
"date": "2021-04-09",
"count": 0
},
{
"date": "2021-04-10",
"count": 0
},
{
"date": "2021-04-11",
"count": 0
},
{
"date": "2021-04-12",
"count": 0
},
{
"date": "2021-04-13",
"count": 10 // this had a count in the initial object
},
...
...
...
]
}
In terms of a function, the closest I have got is
let startDay = moment().format('YYYY-MM-DD');
let endDay = moment().add(14, 'days').format('YYYY-MM-DD');
let startDate = moment(startDay);
let endDate = moment(endDay);
let datesBetween = [];
let startingMoment = startDate;
while(startingMoment <= endDate) {
for (let count = 0; count < 15; count ++) {
// at this point im trying to take 'week' which has the location property and needs property and trying to merge them together... but failed miserably.
if (week.needs[count].date === startingMoment) {
datesBetween.push([startingMoment.clone(), week.needs[count].count]);// clone to add new object
startingMoment.add(1, 'days');
} else {
datesBetween.push([startingMoment.clone(), 0]);// clone to add new object
}
}
}
Can someone see where I went so wrong?
const week = {
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
}
let current = moment();
const allDates = [];
const FORMAT = 'YYYY-MM-DD';
for (let count = 0; count < 14; count++) {
const found = week.needs.find(i => i.date === current.format(FORMAT));
if (found) {
allDates.push(found);
} else {
allDates.push({
date: current.format(FORMAT),
count: 0,
});
}
current.add(1, 'day');
}
week.needs = allDates;
console.log(week);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous"></script>
You could do something like this :
let dates = {
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
};
let day = moment();
for( let i=0; i< 15; i++){
let date = day.add(1, "days").format("YYYY-MM-DD");
console.log(`Looking if ${date} is in array...`)
if(dates.needs.find(obj => obj.date === date)) continue;
console.log(`Adding ${date}`)
dates.needs.push({ date, count : 0 })
}
dates.needs.sort( (a,b) => a.date > b.date ? 1: -1 );
console.log(dates)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
I have a json object which is generated using lowdb. Each json entry has a timestamp. I wan't to get all the entry for yesterday, and today based on the timestamp.
The items variable here is just a json object. Here is a sample
{
"items": [
{
"date": 1596131220030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
},
{
"date": 1596232321030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
}
]
}
I want to get the items from yesterday, and today in this functuin
export async function report(){
try {
const items = db.get('items').value();
return items;
} catch (error) {
console.log(error);
}
}
You can compare with time values for the start of "today" and "yesterday", e.g.
// Return time value for the start of given date, default is today
function getToday(d = new Date()) {
return new Date(+d).setHours(0,0,0,0);
}
// Return time value for the start of day prior to given day, default is today
function getYesterday(d = new Date()) {
let e = new Date(getToday(d));
return e.setDate(e.getDate() - 1);
}
let data = {
"items": [
{"date": 1596085802005, // 30 Jul 2020
"item": "1"
},
{"date": 1596131220030, // 31 Jul 2020
"item": "2"
},
{"date": 1596232321030, // 1 Aug 2020
"item": "3"
}
]
}
// Run as for 1 Aug 2020
let yesterday = getYesterday(new Date(2020,7,1));
let result = data.items.filter(item => item.date >= yesterday);
console.log(result);
Results may vary based on the host timezone offset as the above uses local date values.
You need to parse the date, and compare the difference as follows:
let obj = {
"items": [
{
"date": 1596131220030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
},
{
"date": 1596232321030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
}
]
};
let list = [];
let items = obj.items;
let today = new Date();
for(let i = 0; i < items.length; i++){
var d = new Date(items[i].date);
var diff = Math.floor((d - today) / (1000 * 60 * 60 * 24));
if(diff == 0 || diff == -1)
list.push(items[i].item);
}
console.log(list);
I have JSON data which is structured as below. Intension is to look up a specific datapoint, e.g. annual profit, which is 5000.
I want to do this by finding the column by name, e.g. "profit", identify the column index (3 in the example), and then use the column index to select the nth (3rd) element in the second node ("annual") of the "data" array.
How can I do this using the findIndex() function in Javascript (see the key part of my code below)?
JSON data:
{
"datatable": {
"data": [
[
"AAPL",
"quarterly",
1000,
2000
],
[
"AAPL",
"annual",
5000,
10000
]
],
"columns": [{
"name": "ticker"
"type": "String"
},
{
"name": "timedim"
"type": "String"
},
{
"name": "profit",
"type": "Integer"
},
{
"name": "revenue",
"type": "Integer"
}
]
}
}
JavaScript code:
// daten contains the "data" array of the JSON dataset
// spalten contains the "columns" array of the JSON dataset
var i = spalten.findIndex(obj => obj.name == "profit");
output += '<p>Annual profit AAPL: ' + daten[i] + '</p>';
elroot.innerHTML += output;
You have 2-dimensional array, so, you need two indexes:
const json = {
"datatable": {
"data": [
[
"AAPL",
"quarterly",
1000,
2000
],
[
"AAPL",
"annual",
5000,
10000
]
],
"columns": [{
"name": "ticker",
"type": "String"
},
{
"name": "timedim",
"type": "String"
},
{
"name": "profit",
"type": "Integer"
},
{
"name": "revenue",
"type": "Integer"
}
]
}
}
var profitIndex = json.datatable.columns.findIndex(item => item.name == 'profit');
var annualIndex = json.datatable.data.findIndex(array => array.indexOf('annual') > -1);
var annualProfit = json.datatable.data[annualIndex][profitIndex];
If you need a function, it could look like below:
var getValueFromJson = function (json, columnName, dataMarker) {
var columnIndex = json.datatable.columns.findIndex(item => item.name == columnName);
var dataMarkerIndex = json.datatable.data.findIndex(array => array.indexOf(dataMarker) > -1);
if (columnIndex < 0 || dataMarkerIndex < 0) {
return null;
}
return json.datatable.data[dataMarkerIndex][columnIndex];
}
console.log(getValueFromJson(json, 'profit', 'quarterly'));
console.log(getValueFromJson(json, 'profit', 'annual'));
console.log(getValueFromJson(json, 'revenue', 'quarterly'));
console.log(getValueFromJson(json, 'revenue', 'annual'));
Above code prints:
> 1000
> 5000
> 2000
> 10000
Based on the JSON structure you've given, the following will work. Writing a function would be good if you want to get specific profit based on parameters.
var output = ""
function getProfit(type="annual", column=2) {
var arrForType = yourData.datatable.data.find(arr => arr.indexOf(type) !== -1);
return arrForType[column];
}
var i = yourData.datatable.columns.findIndex(obj => obj.name == "profit");
output += '<p>Annual profit AAPL: ' + getProfit("annual", i) + '</p>';
document.body.innerHTML += output;
You don't need findIndex - just use find and includes like so:
const data = {
"datatable": {
"data": [
[
"AAPL",
"quarterly",
1000,
2000
],
[
"AAPL",
"annual",
5000,
10000
]
],
"columns": [{
"name": "ticker",
"type": "String"
},
{
"name": "timedim",
"type": "String"
},
{
"name": "profit",
"type": "Integer"
},
{
"name": "revenue",
"type": "Integer"
}
]
}
};
function findValue(type) {
return data.datatable.data.find(e => e.includes(type))[2];
}
console.log(findValue("annual"));
console.log(findValue("quarterly"));
This is the basic idea, then if you need to scale obviously you'll need to do this in a nicer way.
let output = '';
// Searches the desired index (refactor as needed)
const index = spalten.findIndex(obj => obj.name == "profit")
// Extract all the profits (if you dont need all just select the desired one)
daten.map(item => output += `<p>${item[1]} profit ${item[0]}: ${item[index]}</p>`)
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 : "";
}));
});
}
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'];
....
}