I have saved this timestamp in a Firestore document:
last_check_mmr: 14 dicembre 2021 15:39:01 UTC+1
How can I check if a day has passed from that date using Javascript?
Since you use a Cloud Function it is quite easy by using Dayjs, the "minimalist JavaScript library that parses, validates, manipulates, and displays dates".
Something like the following, using the diff() method, should do the trick:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const dayjs = require('dayjs');
// Let's imagine you use a scheduled Cloud Funciton
exports.scheduledFunction = functions.pubsub.schedule('...').onRun(async (context) => {
// Get the value of the timestamp, e.g. by fetching a Firestore document
const docRef = ...;
const snap = await docRef.get();
const last_check_mmr = snap.get('last_check_mmr');
const date = dayjs(last_check_mmr.toDate());
const now = dayjs();
console.log(date.diff(now, 'd'));
// If you get a value of 0, it means it is less than a day, if you get -1 or less it is more than a day
if (date.diff(now, 'd') < 0) {
// more than a day
}
return null;
});
Related
Good evening. Im Using JSJoda to calculate the difference between two dates. In the database there is a row where by default, the date is inserted automatically.
I need to create a normal function (without Req, Res object) where each row will be deleted after 60 days.
const cron = require('node-cron');
const JSJoda = require('js-joda');
const {deleteRecord, getAllMessages} = require('../connection/db.js');
exports.deleteMessage = async () => {
/**
* Get all the messages and delete statement
*/
const deleteStatement = 'DELETE FROM ?? WHERE ?? = ?';
const selectStatement = 'SELECT * FROM message';
try
{
const messageList = await getAllMessages(selectStatement);
/**
* Loop over the array of messages and find the date
*/
for (message of messageList) {
let dateTarget = message.dateAdded;
/**
* Convert the date to ISOString() and leave only the dates
*/
let messageDates = dateTarget.toISOString().split('T')[0];
let today = new Date().toISOString().split('T')[0];
let difference = JSJoda.ChronoUnit.DAYS.between(JSJoda.LocalDate.parse(messageDates), JSJoda.LocalDate.parse(today));
while (difference === 0) {
// Problem is here I dont know what should I do
await deleteRecord(deleteStatement, 'message', message.messageID, value);
}
}
}
catch (error)
{
console.log(error);
}
};
In this function I get all the records, and parsed it to the required format by the library. The variable bellow apparently shows the right days, But now I realised that I am stuck.
let difference = JSJoda.ChronoUnit.DAYS.between(JSJoda.LocalDate.parse(messageDates), JSJoda.LocalDate.parse(today));
I dont know how should I proceed with this function.... Where to place it, and the most important, how to select the right messageID that must be deleted.
This is the actual columns from MySQL
I am using this code to get data from a collection by comparing
/* eslint-disable */
const functions = require("firebase-functions");
const admin = require('firebase-admin');
admin.initializeApp();
const database = admin.firestore();
exports.checkForPending = functions.pubsub.schedule('* * * * *').onRun(async (context)
=> {
var currentTime = admin.firestore.Timestamp.now();
var total; //getting time from firebase server
var firebase_time = admin.firestore.Timestamp.now(); // {'_seconds': 123456,
_nanoseconds: 123000000}
// Convert map of nanoseconds and seconds to milliseconds
var firebase_seconds_to_milliseconds = firebase_time._seconds * 1000; // 123456000
var firebase_nanoseconds_to_milliseconds = Math.round(firebase_time._nanoseconds /
1000000) //123
var milliseconds = firebase_seconds_to_milliseconds +
firebase_nanoseconds_to_milliseconds;
var firebase_month = firebase_time.toDate().getMonth();
var unix_to_date_before_buffer = new Date(milliseconds);
var unix_to_date_after_buffer = new Date(milliseconds);
// var unix_to_date = new Date(total);
unix_to_date_before_buffer.setSeconds(0); //coverted from 6:38:23 to 6:38:00
unix_to_date_after_buffer.setSeconds(0);
unix_to_date_after_buffer.setMinutes(unix_to_date_after_buffer.getMinutes() + 1);//coverted from 6:38:23 to 6:39:00
//Want to edit month in this timestamp;
const query =
database.collection("users").doc('IELTS').collection('IELTS').where("next", '>=', unix_to_date_before_buffer).where("next", '<=', unix_to_date_after_buffer); // comparing here
const snapshot = await query.get();
snapshot.forEach(doc => {
console.log(doc.id, '=>', doc.data().name),
queryTest2 = database.collection('rest');
queryTest2.add(
{
'executed': true,
'name': doc.data().name
}
)
});
return null;
});
The am not getting any results in the console. I am wondering why?
I didn't see any new collection 'rest' formed.
The time in the collection of parameter 'next' was 6:38:24 in the collection in the example.
What I am trying to build -
I am making an app for an institute. I am registering users and making a collection which looks like -
collection
(here 'date' is the date of registration and 'next' is the time when The pay will automatically change to 0 because of the starting of next month.)
Now I am running a cloud function that is checking every day if 'next' is equal to the current time of server, then I want to execute something (add a user to a new collection called 'pending'.) and update 'next' to the next month. which should look like this -
edited-paramter
In firebase realtime database, something seemingly basic does not work.
Here is the JS code:
let myDBRef = firebase.database().ref('MyCollection');
newItem = myDBRef.push(),
startTime = firebase.database.ServerValue.TIMESTAMP,
endTime = startTime + 24*3600*1000
newItem.set({
someField:'myFieldValue',
startTime:startTime,
endTime:endTime
});
I expect something like the following in the DB as a result:
-MXb9s2-3mX3XZL_azRv
endTime: 1601691254295
someField: "myFieldValue"
startTime: 1601604854295
But I get this instead:
-MXb9s2-3mX3XZL_azRv
endTime: "[object Object]86400000"
someField: "myFieldValue"
startTime: 1601604854295
What am I doing wrong and how do I need to change the JS code to get the result I expect?
The firebase.database.ServerValue.TIMESTAMP is not the current server-side timestamp, but a marker value that gets translated to the actual server-side timestamp when written to the database.
That means that you can't store calculated values like you do now in a single step. You have two options:
Store the duration instead of the endTime. So:
let myDBRef = firebase.database().ref('MyCollection');
newItem = myDBRef.push(),
startTime = firebase.database.ServerValue.TIMESTAMP,
duration = 24*3600*1000
newItem.set({
someField:'myFieldValue',
startTime:startTime,
duration:duration
});
Store the startTime first, and then calculate the endTime either in the client or in a Cloud Function, that then updates the database. This'd be something like:
let myDBRef = firebase.database().ref('MyCollection');
newItem = myDBRef.push(),
startTime = firebase.database.ServerValue.TIMESTAMP,
duration = 24*3600*1000
newItem.set({
someField:'myFieldValue',
startTime:startTime,
}).then(() => {
newItem.child("startTime").once("value").then((snapshot) => {
newItem.update({ endTime: snapshot.val() + duration });
})
})
I want to deleted a child after a certain time. I know that you need Firebase function to achief this. This is what I got so far:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.removeOldMessages = functions.https.onRequest((req, res) => {
const timeNow = Date.now();
const Ref = admin.database().ref('/Feed');
Ref.once('value', (snapshot) => {
snapshot.forEach((child) => {
if (1000*(Number(child.val()['timestamp']) + Number(child.val()['duration'])) >= timeNow) {
child.ref.set(null);
}
});
});
return res.status(200).end();
});
I want to deleted the child when the duration is over (the duration is in seconds). This is my structure:
Thanks!
You're sending a response to the caller at the end of the function, which will be executed before the data from the database is returned. And Cloud Functions will stop executing your code straight after that res.status(200).end(), so the database cleanup never happens.
To prevent this, only send a response to the caller after all data has been deleted from the database:
exports.removeOldMessages = functions.https.onRequest((req, res) => {
const timeNow = Date.now();
const Ref = admin.database().ref('/Feed');
return Ref.once('value', (snapshot) => {
let updates = [];
snapshot.forEach((child) => {
if (1000*(child.val().timestamp + child.val().duration) >= timeNow) {
updates[child.key] = null;
}
});
return Ref.update(updates).then(() => {
return res.status(200).end();
});
});
});
I highly recommend storing an additional property in your child nodes though, with the precalculated value of timestamp + duration. By having such a property, you can run a query on the nodes that have expired, instead of having to read all child nodes and then filtering in code.
For an example of this, see my answer to Delete firebase data older than 2 hours, and the Cloud Functions example that was based on that.
I'm working on a web application that will visualize data from my Firebase database. But first, I want to be able to "count" the total number of users with a given data so that I can then use that count number in my graphs.
For reference, my database looks like this:
Because I expect separate totals for the required keys, I'm guessing that I'll need separate counters for each one. I've started writing a cloud function to keep track of when a new user is created:
import * as functions from 'firebase-functions'
export const onMessageCreate = functions.database
.ref('/students/{studentID}')
.onCreate((snapshot, context) => {
const userData = snapshot.val()
const afterGrad = userData.afterGrad
const gender = userData.gender
const gradDate = userData.gradDate
const program = userData.program
const race = userData.race
const timeToComplete = userData.timeToComplete
})
But now, I'm extremely lost at how I should go about creating counters. Would something like this suffice, with an individual counter for each constant?
import * as functions from 'firebase-functions'
var counterAfterGrad;
export const onMessageCreate = functions.database
.ref('/students/{studentID}')
.onCreate((snapshot, context) => {
const userData = snapshot.val()
const afterGrad = userData.afterGrad
var counterAfterGrad++
})
Or should I be thinking about using a transaction in this case? I'm really not sure of the best way, and would really appreciate some help.
Yes, you should use a transaction. See the documentation here: https://firebase.google.com/docs/database/web/read-and-write#save_data_as_transactions and https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction
For counting the overall number of users you could do as follows:
export const onMessageCreate = functions.database
.ref('/students/{studentID}')
.onCreate((snapshot, context) => {
const userData = snapshot.val()
const afterGrad = userData.afterGrad
const allUsersCounterRef = admin
.database()
.ref('allUsersCounter');
return allUsersCounterRef
.transaction(counter_value => {
return (counter_value || 0) + 1;
})
})
Note that you may have to take into consideration the deletion of a user.
You could very well have several counters, for example by "gender" (male/female) and by "program". You would then use an object in the transaction as follows:
exports.onMessageCreate = functions.database
.ref('/students/{studentID}')
.onCreate((snapshot, context) => {
const userData = snapshot.val();
const countersRef = admin.database().ref('counters');
return countersRef.transaction(currentData => {
currentData[userData.gender] = (currentData[userData.gender] || 0) + 1;
currentData[userData.program] = (currentData[userData.program] || 0) + 1;
return currentData;
});
});