BSON.Timestamp conversion issue in Nodejs Mongodb Stitch? - javascript

I am using stitch function to get the last 7 days from event collection.below is my code.this is execute in stitch function.
exports = async function() {
var events = context.services.get("mongodb-atlas").db("utilo").collection("events");
var today = new Date();
var lastWeek = BSON.Timestamp(today.setDate(today.getDate()-7),0);
console.log(lastWeek);
var document = null;
do{
document = await cursor.next();
if(document){
var result = {};
result.community = document._id;
result.data.newUsersCount = await events.count({community:document._id,type:"join",status:"completed",ts:{$gt:lastWeek}});
}}
}
In the above code, I tried to get last 7 days records from event collection.Here (today.setDate(today.getDate()-7),0) getting the correct Timestamp value but after adding BSON.Timestamp, the timestamp will change to lower year or higher year like either 2004 or 2024. without changing the Timestamp value, can we convert to the Timestamp?
How can i store value in last week like TImestamp(1520801145,0)?
or How to write the code for get the last 7 days record from events collection (ts stored in timestamp)

Related

How to query a timestamp field by year in Feathersjs?

Currently I have a timestamp field with value format like 1479664146607.
What I wanted to do is to get all data with timestamp that has a year of let's say 2017.
My current code is non-performant. It gets all the data, and then uses a filter method.
Let's say I got 2000+ records.
const records = []; // all records
const data = records.filter(r => new Date(r).getYear == '2017');
While this code works, it kills the server.
My database is nedb and using feathersjs, I can actually get equality items by
app.service('messages').find({
query: {
timestamp: '2017'
}
});
This code will not work because it will search for the exact year. I am looking for a way to convert the timestamp field to a year before searching it in the database.
Okay, so what I did is to use the $gt and $lt operators.
Let's say we want to get all data in year 2018.
Using momentjs, I did something like this:
const year = '2018';
// Get previous year based on given year
const previousYear = moment(year, 'YYYY').subtract(1, 'year').format('YYYY');
// Get next year based on given year
const nextYear = moment(year, 'YYYY').add(1, 'year').format('YYYY');
// get full ending date of previous year
const endOfPreviousYear = moment(previousYear, 'YYYY').endOf('year').format('x');
// get full starting date of next year
const startOfNextYear = moment(nextYear, 'YYYY').startOf('year').format('x');
// get data where year is greater than `endOfPreviousYear` and less than `startOfNextYear`
const yearQuery = {
$gt: +endOfPreviousYear,
$lt: +startOfNextYear
}
app.service('messages').find({
query: {
timestamp: yearQuery
}
});

angularfire retrieving data timestamp to timestamp

I am trying to retrieve data using angularfire .I.e retrieve all data in an array from one timestamp to another timestamp.
var messageOfEachUser =firebase.database().ref().child("messages").child(data.key);
var currentTime = firebase.database.ServerValue.TIMESTAMP;
var query = messageOfEachUser.queryOrderedByChild("time").queryStartingAtValue(currentTime).queryEndingAtValue(lastSeenValueFromNode);
var listOfNewMessages = $firebaseArray(query);
console.log(listOfNewMessages);
Here in the above code connection to firebase. And querying data from a currenTime to lastSeenValueFromNode where lastSeenValueFromNode contains a timestamp when a user visited this node last time.
You cannot user firebase.database.ServerValue.TIMESTAMP in the way you are doing here. It is really just a marker value, that will be converted into the actual timestamp when your operation reaches the server.
Since you are using timestamps, you can simply use the local time as a rough estimate:
var currentTime = Date.now();
Alternatively, you can use Firebase's built-in latency detection value and get a value that is closer to ServerValue.TIMESTAMP:
var offsetRef = firebase.database().ref(".info/serverTimeOffset");
offsetRef.on("value", function(snap) {
var offset = snap.val();
var currentTime = Date.now() + offset;
});

Function to iterate over an array of dates produces unexpected results

I have a CloudCode function that is called from my iOS app. The function is supposed to create a "checkin" record and return a string to represent the last 30 days of check-ins and missed days.
The strange thing is that sometimes I get the expected results and sometimes I do not. It makes me think that there is some issue with the may I am using timezones - since that could result in a different set of "days in the past" depending on what time I run this function and what time of day I checked-in in the past. But I'm baffled and could use some help here.
It's also confusing me that I do not see all of my console.log() results appear in the parse log. Is that normal?? For example, in the for loop, I can uncomment the console.log entry and call the function but I will not see all of the days in the past listed - but they are included in the final array and text string.
Here is my complete function. Any help and suggestions are appreciated.
/* Function for recording a daily check in
*
* Calculates the number of days missed and updates the string used to display the check-in pattern.
* If no days missed then we increment the current count
*
* Input:
* "promiseId" : objectID,
* "timeZoneDifference" : String +07:00
*
* Output:
* JSON String eg. {"count":6,"string":"000000000000001111101010111111"}
*
*/
Parse.Cloud.define("dailyCheckIn", function(request, response) {
var promiseId = request.params.promiseId;
var timeZoneDifference = request.params.timeZoneDifference;
var currentUser = Parse.User.current();
if (currentUser === undefined) {
response.error("You must be logged in.");
}
if (timeZoneDifference === undefined || timeZoneDifference === "") {
//console.log("timeZoneDifference missing. Set to -07:00");
timeZoneDifference = '' + '-07:00'; // PacificTime as string
}
var moment = require('cloud/libs/moment.js');
// Query for the Promise
var Promise = Parse.Object.extend("Promise");
var queryforPromise = new Parse.Query(Promise);
queryforPromise.get(promiseId, {
success: function(promis) {
// Initialize
var dinarowString = "";
var dinarowCount = 0;
// Last Check In date from database (UTC)
var lastCheckInUTC = promis.get("lastCheckIn");
if (lastCheckInUTC === undefined) {
lastCheckInUTC = new Date(2015, 1, 1);
}
// Use moment() to convert lastCheckInUTC to local timezone
var lastCheckInLocalized = moment(lastCheckInUTC.toString()).utcOffset(timeZoneDifference);
//console.log('lastCheckIn: ' + lastCheckInUTC.toString());
//console.log('lastCheckInLocalized: ' + lastCheckInLocalized.format());
// Use moment() to get "now" in UTC timezone
var today = moment().utc(); // new Date();
//console.log('today: ' + today.format());
// Use moment() to get "now" in local timezone
var todayLocalized = today.utcOffset(timeZoneDifference);
//console.log('todayLocalized: ' + todayLocalized.format());
// 30 days in the past
var thirtydaysago = moment().utc().subtract(30, 'days');
//console.log("thirtydaysago = " + thirtydaysago.format());
// 30 days in the past in local timezone
var thirtydaysagoLocalized = thirtydaysago.utcOffset(timeZoneDifference);
//console.log('thirtydaysagoLocalized: ' + thirtydaysagoLocalized.format());
// Calculate the number of days since last time user checked in
var dayssincelastcheckin = todayLocalized.diff(lastCheckInLocalized, 'days');
//console.log("Last check-in was " + dayssincelastcheckin + " days ago");
// Function takes an array of Parse.Objects of type Checkin
// itterate over the array to get a an array of days in the past as numnber
// generate a string of 1 and 0 for the past 30 days where 1 is a day user checked in
function dinarowStringFromCheckins(checkins) {
var days_array = [];
var dinarowstring = "";
// Create an array entry for every day that we checked in (daysago)
    for (var i = 0; i < checkins.length; i++) {
var checkinDaylocalized = moment(checkins[i].get("checkInDate")).utcOffset(timeZoneDifference);
var daysago = todayLocalized.diff(checkinDaylocalized, 'days');
// console.log("daysago = " + daysago);
days_array.push(daysago);
}
console.log("days_array = " + days_array);
// Build the string with 30 day of hits "1" and misses "0" with today on the right
    for (var c = 29; c >= 0; c--) {
if (days_array.indexOf(c) != -1) {
//console.log("days ago (c) = " + c + "-> match found");
dinarowstring += "1";
} else {
dinarowstring += "0";
}
}
return dinarowstring;
}
// Define ACL for new Checkin object
var checkinACL = new Parse.ACL();
checkinACL.setPublicReadAccess(false);
checkinACL.setReadAccess(currentUser, true);
checkinACL.setWriteAccess(currentUser, true);
// Create a new entry in the Checkin table
var Checkin = Parse.Object.extend("Checkin");
var checkin = new Checkin();
checkin.set("User", currentUser);
checkin.set("refPromise", promis);
checkin.set("checkInDate", today.toDate());
checkin.setACL(checkinACL);
checkin.save().then(function() {
// Query Checkins
var Checkin = Parse.Object.extend("Checkin");
var queryforCheckin = new Parse.Query(Checkin);
queryforCheckin.equalTo("refPromise", promis);
queryforCheckin.greaterThanOrEqualTo("checkInDate", thirtydaysago.toDate());
queryforCheckin.descending("checkInDate");
queryforCheckin.find().then(function(results) {
var dinarowString = "000000000000000000000000000000";
var dinarowCount = 0;
if (results.length > 0) {
dinarowString = dinarowStringFromCheckins(results);
dinarowIndex = dinarowString.lastIndexOf("0");
if (dinarowIndex === -1) { // Checked in every day in the month!
// TODO
// If the user has checked in every day this month then we need to calculate the
// correct streak count in a different way
dinarowString = "111111111111111111111111111111";
dinarowCount = 999;
} else {
dinarowCount = 29 - dinarowIndex;
}
}
// Update the promise with new value and save
promis.set("dinarowString", dinarowString);
promis.set("dinarowCount", dinarowCount);
promis.set("lastCheckIn", today.toDate());
promis.save().then(function() {
response.success(JSON.stringify({
count: dinarowCount,
string: dinarowString
}));
});
}, function(reason) {
console.log("Checkin query unsuccessful:" + reason.code + " " + reason.message);
response.error("Something went wrong");
});
}); // save.then
},
error: function(object, error) {
console.error("dailyCheckIn failed: " + error);
response.error("Unable to check-in. Try again later.");
}
});
});
There's too much going on in your question to answer adequately, but I will be nice and at least point out a few errors that you should look into:
You take input in terms of a fixed offset, but then you are doing operations that subtract 30 days. It's entirely possible that you will cross a daylight saving time boundary, in which case the offset will have changed.
See "Time Zone != Offset" in the timezone tag wiki. In moment, you can use time zones names like "America/Los_Angeles" with the moment-timezone add-on.
From your example, I'm not even sure if time zone even matters or not for your use case.
You should not convert the Date to a string just to parse it again. Moment can accept a Date object, assuming the Date object was created correctly.
moment(lastCheckInUTC.toString()).utcOffset(timeZoneDifference)
becomes
moment(lastCheckInUTC).utcOffset(timeZoneDifference)
Since Date.toString() returns a locale-specific, implementation-specific format, you'll also see you have a warning in the debug console from moment.
As for the rest, we can't run your program and reproduce the results, so there's not much we can do to help. You need to start by debugging your own program, and then try to reproduce your error in a Minimal, Complete, and Verifiable example. Chances are, you'll solve your own problem along the way. If not, then you will have something in a better state to share with us.
I am answering my own question as I have found the solution.
I had two questions. The first was "why do I get unexpected (incorrect) results" and I suspected that it was related to the way I am using timezones. I would see different results from day to day depending on what time I check in.
The problem is actually related to the way that moment().diff() works. Diff does not calculate "days" the way I expected it to. If I compare 2am today with 11pm yesterday diff will say 0 days because it is less than 24 hours diff. If I compare 1am on Thursday with 8pm on the previous Monday, diff will report 2 days - not 3 as I expected. It's a precision issue. Diff thinks 2.4 days is 2 days ago. But it is more than 2 therefor it is 3 days ago.
We found that the easiest solution is to compare the two dates at midnight rather than at the actual time of day that is recorded in the database. This yields correct results for days. The rest of the code is working fine.
//Find start time of today's day
var todayLocalizedStart = todayLocalized.startOf('day');
    for (var i = 0; i < checkins.length; i++) {
var checkinDaylocalized = moment(checkins[i].get("checkInDate")).utcOffset(timeZoneDifference);
//Find start time of checkIn day
var checkinDaylocalizedStart = checkinDaylocalized.startOf('day');
//Find number of days
var daysago = todayLocalizedStart.diff(checkinDaylocalizedStart, 'days');
// console.log("daysago = " + daysago);
days_array.push(daysago);
}
The second question I had was "is it normal to not see every console.log at runtime". I've talked with other Parse.com users and they report that Parse is inconsistent in logging. I was spending a lot of time debugging "problems" that were simply Parse not logging correctly.
Thanks to everyone that contributed to the answer.
I did make one other change - but it was not a bug. I replaced the query limit from 30 days in the past to simply "30". It's just a bit simpler with one less calculation.

Select specific object from a JSON array

I'm working with a windows 8 app using Java Script
I'm get some rss and convert it to JSON format objects using Google API. So Then I got some sort of object array of JSON for that rss feed. I need to do is I want to select few objects among all objects of the array according to the published day. That means I want to get all objects from the array which published before 6 hours(In between current date and before 6 hours except other objects).. Can anyone help me for do that..?
I use this code for get all objects.
function loadNews() {
var allEntries = [];
var pendingRequestCount = listOfFeed.length;
var onRequestFinished = function () {
pendingRequestCount--;
if (pendingRequestCount === 0) {
processItems(allEntries);
}
};
for (var x = 0; x < listOfFeed.length; x++) {
feedburnerUrl = listOfFeed[x].url,
feedUrl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&output=json&num=999&q=" + encodeURIComponent(feedburnerUrl);
WinJS.xhr({
url: feedUrl,
responseType: "rss/json"
}).done(function complete(result) {
var jsonData = JSON.parse(result.response);
var entries = jsonData.responseData.feed.entries;
allEntries = allEntries.concat(entries);
allEntries.sort(function (entry1, entry2) {// Compare the entries by publish date
return Date.parse(entry2.publishedDate) - Date.parse(entry1.publishedDate); // return get milisecond
});
onRequestFinished();
});
} //loop x finish}
}
According to the above cord, allEntries provide JSON object array
Very thankful for the your answers
You're going to have to loop through every entry and compare the dates. For each date that passes your test, add it to another array. E.g.
var newEntries = JSON.parse(result.response),
filteredEntries = [],
i,
testDate = new Date();
testDate = testDate.setHours(testDate.getHours() - 6);
for(i = 0; i < newEntries.length; i++) {
if(newEntries[i].publishedDate > testDate) {
filteredEntries.push(newEntries[i]);
}
}
new Date() always returns the current date
Date.getHours() returns the hour component of the date
Date.setHours(hour) sets the hour component of the date
If hour is a negative value, the date will go to the previous day. For instance if your date was 2013-5-3 04:33 setting the hour component to -2 will change the date to 2013-5-2 22:33
In the example above, if the time was 2:45 a.m., it will set the time component to -4, which would cause it to test against 8:45 p.m. the previous day.

Convert UTC time to specific zone

I have the following data:
var currentTime: 2013-07-11 15:55:36+00:00
var currentTimezone: Africa/Asmera
I need a way to convert the currentTime in UTC to a new time based on currentTimezone.
I've looked into Timezone.js and I'm having trouble implementing it (the directions on the site are a little ambiguous)
The code for the function I'm intending on using is included. Thanks :)
<script>
$("#storeTime").click(function(){
storeCurrentTime();
})
$("#getTime").click(function(){
retrieveTime();
})
$("#storeTimezone").click(function(){
var yourTimezone = $('#timezone-select').find(":selected").text();
tz = yourTimezone.toString();
storeCurrentTimezone(tz);
})
$("#convertTime").click(function(){
//get the most recent UTC time, clean it up
var currentTime = $('#RetrievedTime').html();
currentTime = currentTime.split(": ")[1];
$('#convertedTime').html("Converted Time: " + currentTime);
//get the saved timezone
var currentTimezone = $('#storedTimezone').html();
})
</script>
You're going to need to know the timezone offset, so some sort of dictionary with strings to numbers.
// assuming your dictionary says 3 hours is the difference just for example.
var timezoneDiff = 3;
Then you can just make a new time like this
// Assuming you have the proper Date string format in your date field.
var currentDate = new Date(currentTime);
// Then just simply make a new date.
var newDate = new Date(currentDate.getTime() + 60 * 1000 * timezoneDiff);
Update
I've written a javascript helper for this which you can find at:
http://heuuuuth.com/projects/OlsonTZConverter.js
I pulled the timezone data from the wikipedia page https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
Usage is as follows once included the script.
var offset = OlsonTZConverter.GetUTCOffset("Africa/Asmera");
or if there is Daylight Savings in effect:
var offset = OlsonTZConverter.GetUTCOffset("Africa/Asmera",true);
These will throw if you pass an invalid timezone, but you can check if a timezone is valid with:
var isValid = OlsonTZConverter.Contains("Africa/Asmera");
or just look at the entire dictionary with:
var tzDict = OlsonTZConverter.ListAllTimezones();
Hope this maybe saves someone some time sometime :).

Categories