CouchDB get stats for dates in reduce function - javascript

im currently starting with couchDB and have a problem building a reduce function on dates.
The database consists of timeline data for different locations. Every entry has a 'locationId' (String), a 'datetime' ( Array saved in lexicographic form like [year,month,day,hour,minute,sec]), a value (double)
i want to find out, which is the lowest and highest datetime for every location where a value exist. The timeline values have different start- and enddates.
In a first attempt i used _stats on milliseconds:
map:
function(doc) {
emit(doc.locationId, new Date(doc.datetime[0],doc.datetime[1],doc.datetime[2], doc.datetime[3], doc.datetime[4], doc.datetime[5]).getTime() ) }
reduce: _stats
this delivers the correct min and max milliseconds per locationId.
Now i want to have the output in a more readable form (formatted date string)
I tried different ways, here is the last one:
- map delivers locationId as key and a Date as value
- reduce converts every Date to milliseconds,
find the earlist date using Math.min,
re-converting milliseconds into Date and return
map:
function(doc) {
emit(doc.locationId, new Date(doc.datetime[0], doc.datetime[1],doc.datetime[2], doc.datetime[3], doc.datetime[4], doc.datetime[5]) ) }
reduce:
function(keys, values) {
var timestamps = new Array(values.length);
var i = 0;
var date;
for( date in values ) { timestamps[i] = date.getTime(); i++; }
var min = Math.min.apply(null, timestamps);
return new Date(min);
}
This results in 'null' for value.
is it possible to have a formatted date output for this case?

I've found the solution:
map:
function(doc) {
if (doc.datetime && doc.plantId)
emit(doc.plantId, [new Date(doc.datetime[0],doc.datetime[1]-1,doc.datetime[2],doc.datetime[3],doc.datetime[4],doc.datetime[5],0), new Date()] )
}
reduce:
function(keys, values) {
values.sort();
var date = [values[0][0], values[values.length-1][0]];
return date;
}
result: (key=locationID, value=[earliestDate, latestDate])

Related

the index value is shown on terminal but is undefined while trying to utilize in code

I'm trying to work with some data that has close bindings to dates. As shown in the snippet down below I'm trying to find the index of the closest day to today. I'm using date-fns utility library for this job. While I'm trying to log the closestIndex from it works fine and got an output in the terminal but while I'm trying to utilize the value of closestIndex I got an error that says closestIndex is undefined.
Any Ideas would be very appreciated.
import * as dateFns from 'date-fns';
const today = new Date().getTime();
const dates = [
2022-04-10T14:07:12.276Z,
2022-04-10T14:07:06.967Z,
2022-04-10T14:07:04.663Z,
2022-04-10T14:07:03.040Z,
2022-04-10T14:07:01.420Z,
2022-04-10T14:06:59.869Z,
2022-04-10T14:06:53.223Z
]
const closestIndex = dateFns.closestTo(today, dates);
console.log(closestIndex); // => 0
console.log(dates[closestIndex]); // => undefined could not be used as index value
You should use real Date objects inside your array (rather than ISO-8601 values which are not even quoted) and use closestIndexTo instead of closestTo (which will return the Date value itself rather than its index in the array)
const today = new Date().getTime();
const dates = [
new Date('2022-04-10T14:07:12.276Z'),
new Date('2022-04-10T14:07:06.967Z'),
new Date('2022-04-10T14:07:04.663Z'),
new Date('2022-04-10T14:07:03.040Z'),
new Date('2022-04-10T14:07:01.420Z'),
new Date('2022-04-10T14:06:59.869Z'),
new Date('2022-04-10T14:06:53.223Z')
]
const closestIndex = dateFns.closestIndexTo(today, dates);
console.log(closestIndex); // => 0
console.log(dates[closestIndex]); // => "2022-04-10T14:07:12.276Z"
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.js"></script>

Javascript: divide object date value per day

Hi Everyone,
I have this object:
{"2017-07-09 00:00:00":4,"2017-07-09 09:00:00":1,"2017-07-09 10:00:00":4,"2017-07-09 11:00:00":3,"2017-07-09 12:00:00":16,"2017-07-09 13:00:00":4,"2017-07-09 14:00:00":6,"2017-07-09 15:00:00":5,"2017-07-09 16:00:00":7,"2017-07-09 17:00:00":21,"2017-07-09 18:00:00":25,"2017-07-09 19:00:00":1,"2017-07-10 09:00:00":11,"2017-07-10 10:00:00":4,"2017-07-10 11:00:00":21,"2017-07-10 12:00:00":22,"2017-07-10 13:00:00":23,"2017-07-10 14:00:00":42,"2017-07-10 15:00:00":14,"2017-07-10 16:00:00":36,"2017-07-10 17:00:00":21,"2017-07-10 18:00:00":5,"2017-07-11 09:00:00":16,"2017-07-11 10:00:00":7,"2017-07-11 11:00:00":26,"2017-07-11 12:00:00":34,"2017-07-11 13:00:00":39,"2017-07-11 14:00:00":39,"2017-07-11 15:00:00":30,"2017-07-11 16:00:00":33,"2017-07-11 17:00:00":22,"2017-07-11 18:00:00":1}
I'm trying to divide it per day and get something like this:
First create an array for the day which is 24 hours:
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]
And than calculate how many day is in the object above and get a value for each hours and return something like below. In the object I have 3 days, so I need to return 3 arrays for each days:
[4,0,0,0,0,0,0,0,0,1,10,3,16,...],
[0,0,0,0,0,0,0,0,0,11,4,21,22,23,42,...]
[0,0,0,0,0,0,0,0,0,16,7,26,34,39,39,30,..]
For each hours which is not in the object data return 0 and for each hours that exist return the specified value on the object.
for example on the object the time starts from "2017-07-09 00:00:00":4 and it has the value of 4 and for each hours between that and "2017-07-09 09:00:00":1
return 0.
Any help appreciated. Thanks a lot for your time
You have first to loop into each keys of your object.
After that many solutions, one is to convert your keys into Date object and compare the hour of your object in a for loop.
And retrieve the right data by reconverting your Date obj into your obj property.
Edit
Access your property value without function by using Object.keys and findIndex
I've maybe misunderstand your requirement, but you've a good example
of how to do ;-)
Example of solution
var data ={"2017-07-09 00:00:00":4,"2017-07-09 09:00:00":1,"2017-07-09 10:00:00":4,"2017-07-09 11:00:00":3,"2017-07-09 12:00:00":16,"2017-07-09 13:00:00":4,"2017-07-09 14:00:00":6,"2017-07-09 15:00:00":5,"2017-07-09 16:00:00":7,"2017-07-09 17:00:00":21,"2017-07-09 18:00:00":25,"2017-07-09 19:00:00":1,"2017-07-10 09:00:00":11,"2017-07-10 10:00:00":4,"2017-07-10 11:00:00":21,"2017-07-10 12:00:00":22,"2017-07-10 13:00:00":23,"2017-07-10 14:00:00":42,"2017-07-10 15:00:00":14,"2017-07-10 16:00:00":36,"2017-07-10 17:00:00":21,"2017-07-10 18:00:00":5,"2017-07-11 09:00:00":16,"2017-07-11 10:00:00":7,"2017-07-11 11:00:00":26,"2017-07-11 12:00:00":34,"2017-07-11 13:00:00":39,"2017-07-11 14:00:00":39,"2017-07-11 15:00:00":30,"2017-07-11 16:00:00":33,"2017-07-11 17:00:00":22,"2017-07-11 18:00:00":1}
var dataKeys = Object.keys(data);
var dataKeysParsed = dataKeys.map(function(d){
return new Date(d);
});
var res =[];
for (var i=0;i<=23;i++){
var id = dataKeysParsed.findIndex(function(k){
return k.getHours() == i
});
res.push(id > -1 ? data[dataKeys[id]] : 0);
}
console.log(res);

Highlight multiple options in Cal Heatmap

I have an array of Javascript datetime objects which I want to display on a cal-heatmap. For this, i've done the following:
var startTimes = [] //array of datetimes to show
var cal = new CalHeatMap();
cal.init({
itemSelector: '.heat-map',
domain: 'day',
subDomain: 'hour',
range: range,
start: new Date(startTimes[0]),
highlight: new Date(startTimes[0])
});
for (s in startTimes) {
cal.highlight(cal.options.highlight.push(new Date(startTimes[s])));
}
This however, doesn't seem to work as only the first date gets marked.
Note that push returns the new length of the array and not the element you just added to it.
According to this and the doc of cal-heatmap/#highlight which states that the method expects a date, I guess your code should be:
for (s in startTimes) {
var date = new Date(startTimes[s]);
cal.options.highlight.push(date);
cal.highlight(date);
}

Merge two object arrays for Chart

I've two arrays which I'm going to merge and then load in chart.
range = date array generated from moment.js, there is date of every day in example one month or specific date range with one another attribute count: "0"
data = fetched data from database through backbone
Now I want set atrribute count from data count, where date is same in both arrays.
I'm using lodash...
_.forEach(range, function(n) {
console.log(n.date.substring(0, date.length-6));
// IF n.date = date from data replace count to value from data array
});
Thanks for any help
You can use _.find to match your items in the range to the ones in the data.
_.forEach(range, function(r) {
var d = _.find(data, {date: r.date}); //Find an item in "data" with date matching r.date
if(d) {
r.count = d.count;
}
});

Better data structure to handle this array

I have an array of data get from the server(ordered by date):
[ {date:"2012-8", name:"Tokyo"}, {date:"2012-3", name:"Beijing"}, {date:"2011-10", name:"New York"} ]
I'd like to :
get the name of the first element whose date is in a given year, for example, given 2012, I need Tokyo
get the year of a given name
change the date of a name
which data structure should I use to make this effective ?
because the array could be large, I prefer not to loop the array to find something
Since it appears that the data is probably already sorted by descending date you could use a binary search on that data to avoid performing a full linear scan.
To handle the unstated requirement that changing the date will then change the ordering, you would need to perform two searches, which as above could be binary searches. Having found the current index, and the index where it's supposed to be, you can use two calls to Array.splice() to move the element from one place in the array to another.
To handle searches by name, and assuming that each name is unique, you should create a secondary structure that maps from names to elements:
var map = {};
for (var i = 0, n = array.length; i < n; ++i) {
var name = array[i].name;
map[name] = array[i];
}
You can then use the map array to directly address requirements 2 and 3.
Because the map elements are actually just references to the array elements, changes to those elements will happen in both.
Assuming you are using unique cities, I would use the city names as a map key:
cities = {
Tokyo: {
date: "2012-8"
},
New York: {
date: "2011-10"
}
}
To search by date:
function byDate(date) {
for(el in cities) {
if(cities.hasOwnProperty(el) && cities[el].date === date)
return el;
}
}
Just for the record: without redesigning your date structure you could use sorting combined with the Array filter or map method:
function sortByDate(a,b){
return Number(a.date.replace(/[^\d]+/g,'')) >
Number(b.date.replace(/[^\d]+/g,''));
}
var example = [ {date:"2012-8", name:"Tokyo"},
{date:"2012-3", name:"Beijing"},
{date:"2011-10", name:"New York"} ]
.sort(sortByDate);
//first city with year 2012 (and the lowest month of that year)
var b = example.filter(function(a){return +(a.date.substr(0,4)) === 2012})[0];
b.name; //=> Beijing
//year of a given city
var city = 'Tokyo';
var c = example.filter(function(a){return a.city === city;})[0];
c.year; //=> 2012
//change year of 'New York', and resort data
var city = 'New York', date = '2010-10';
example = example.map(
function(a){if (a.name === city) {a.date = date;} return a;}
).sort(sortByDate);

Categories

Resources