Ok, I have a useInterval (custom hook) that will delete a document from firestore after a given time is milliseconds. It works fine if I set it to 10 seconds, 1 minute.
However, when I set it to delete the document a month after it was created, it looks like it creates the document and gets deleted right away.
How can I set my interval to delete the document after a month from when it was created?
const docRef = firestore.doc(`posts/${id}`)
const deleDoc = () => docRef.delete();
//******************************************************************* */
//? Deleting post after a month(time managed in milliseconds)
const now = createdAt.seconds * 1000;
const monthFromNow = 2628000000;
const then = now + monthFromNow;
const timeLeft = then - Date.now();
//?custom hook
useInterval(() => {
docRef.delete();
}, timeLeft);
You can create a task which hits one of your cloud function endpoint using Cloud Task. You can set it to hit the API every 1 min.
In the API you can pull up all the documents which are older than 1 month and delete them using the above logic.
Related
I encountered a difficult problem when trying to write an electron application. The following is a detailed description of the problem:
I plan to load a clock on the page of the electron rendering process. Just like our system time, it will refresh every second, 60 seconds is one minute, and so on, but I don’t use the system time, I use a current Time API, the json data returned by this API interface is the current time. I wrote a set of asynchronous execution functions in the main process main.js to get the data passed by this API. The following is the main process main.js Asynchronous get time API code:
const request = net.request('http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json')
request.on('response', (response) => {
console.log(response.statusCode);
console.log(response.headers);
response.on('data', (chunk) => {
let result = JSON.parse(chunk).result;
let datetime = result.datetime_1;
let week = result.week_4;
console.log(datetime, week)
mainWindow.webContents.send('datetime', { datetime, week });
})
response.on('end', () => {
console.log('end');
})
})
request.end();
The console information displayed by the main process is as follows:
200
{
server: 'nginx',
date: 'Thu, 06 May 2021 01:38:00 GMT',
'content-type': 'application/json; charset=utf-8;',
'transfer-encoding': 'chunked',
connection: 'keep-alive',
'access-control-allow-origin': '*'
}
2021-05-06 09:38:01 Thursday
end
Then after requesting this API, it will respond with a timestamp of the current time. After the main process obtains this timestamp, it will be sent to my rendering process through webContents.send. The following is the code sent by the main process to the rendering process:
mainWindow.webContents.send('datetime', { datetime, week });
The rendering process obtains the time data sent by the main process through ipcRenderer.on, and then formats this timestamp and outputs it to my rendering process page. I wrote this set of code as a function as follows:
function getNetTime() {
//Get the date and time passed by the main process
ipcRenderer.on('datetime', (event, arg) => {
let datetime = arg.datetime; //Get date and time
let week = arg.week; //Get the day of the week
let year = datetime.substring(0, 4); //Get year
let month = datetime.substring(5, 7); //Get month
let day = datetime.substring(8, 10); //Get the day
let hour = datetime.substring(10, 13); //Get hour
let min = datetime.substring(14, 16); //Get minutes
let sec = datetime.substring(17, 19); //Get seconds
let weekday = ""; //Get Chinese weekday
const timeText = document.querySelector('#timeText')
// console.log(datetime);
// console.log(week);
// console.log(year,month,day,hour,min);
switch (week) {
case'Monday':
weekday ='Monday';
break;
case'Tuesday':
weekday ='Tuesday';
break;
case'Wednesday':
weekday ='Wednesday';
break;
case'Thursday':
weekday ='Thursday';
break;
case'Friday':
weekday ='Friday';
break;
case'Saturday':
weekday ='Saturday';
break;
case'Sunday':
weekday ='Sunday';
break;
}
timeText.innerHTML =`${year}year${month}month${day}day ${weekday}${hour}:${min}:${sec}`;
});
The problem now encountered is that although the current time can be displayed normally on the page of the rendering process, it cannot be automatically refreshed. I want to set it to refresh every 1000 milliseconds through setTimeout or setInterval, which is equivalent to one step in 1 second of the clock. But it has no effect. The current time can only be displayed when the program is reopened, and it cannot be automatically refreshed. The following is the code of setInterval:
window.onload = () => {
getNetTime();
setInterval(getNetTime(),1000)
}
The above is the problem I am encountering now. Electron is also just getting in touch. I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
The problem you're experiencing has nothing to do with Electron or how you request the data from the API. It's about how you set your interval.
The setInterval() function requires a function or a string of code as a parameter. However, you are specifying getNetTime() as the code it should call. This is not a function. It is a function call and will be evaluated before setInterval() is called. This will not do anything because the return type of getNetTime() is undefined.
To mitigate this, you can use a function, an arrow function or just leave out the parentheses. Whatever you choose is up to your liking.
setInterval (getNetTime, 1000);
// or
setInterval (() => getNetTime (), 1000);
// or
setInterval (function () { getNetTime (); }, 1000);
I have an app where one user hosts a game, and then other users can vote on questions from the host. From the moment the host posts the question, the players have 20 seconds to vote.
How can I show a countdown timer on all player's screens and keep them synchronized with the host?
Many developers get stuck on this problem because they try to synchronize the countdown itself across all users. This is hard to keep in sync, and error prone. There is a much simpler approach however, and I've used this in many projects.
All each client needs to show its countdown timer are three fairly static pieces of information:
The time that the question was posted, which is when the timer starts.
The amount of time they need to count from that moment.
The relative offset of the client to the central timer.
We're going to use the server time of the database for the first value, the second value is just coming from the host's code, and the relative offset is a value that Firebase provides for us.
The code samples below are written in JavaScript for the web, but the same approach (and quite similar code) and be applied in iOS, Android and most other Firebase SDKs that implement realtime listeners.
Let's first write the starting time, and interval to the database. Ignoring security rules and validation, this can be as simple as:
const database = firebase.database();
const ref = database.ref("countdown");
ref.set({
startAt: ServerValue.TIMESTAMP,
seconds: 20
});
When we execute the above code, it writes the current time to the database, and that this is a 20 second countdown. Since we're writing the time with ServerValue.TIMESTAMP, the database will write the time on the server, so there's no chance if it being affected by the local time (or offset) of the host.
Now let's see how the other user's read this data. As usual with Firebase, we'll use an on() listener, which means our code is actively listening for when the data gets written:
ref.on("value", (snapshot) => {
...
});
When this ref.on(... code executes, it immediately reads the current value from the database and runs the callback. But it then also keeps listening for changes to the database, and runs the code again when another write happens.
So let's assume we're getting called with a new data snapshot for a countdown that has just started. How can we show an accurate countdown timer on all screens?
We'll first get the values from the database with:
ref.on("value", (snapshot) => {
const seconds = snapshot.val().seconds;
const startAt = snapshot.val().startAt;
...
});
We also need to estimate how much time there is between our local client, and the time on the server. The Firebase SDK estimates this time when it first connects to the server, and we can read it from .info/serverTimeOffset in the client:
const serverTimeOffset = 0;
database.ref(".info/serverTimeOffset").on("value", (snapshot) => { serverTimeOffset = snapshot.val() });
ref.on("value", (snapshot) => {
const seconds = snapshot.val().seconds;
const startAt = snapshot.val().startAt;
});
In a well running system, the serverTimeOffset is a positive value indicating our latency to the server (in milliseconds). But it may also be a negative value, if our local clock has an offset. Either way, we can use this value to show a more accurate countdown timer.
Next up we'll start an interval timer, which gets calls every 100ms or so:
const serverTimeOffset = 0;
database.ref(".info/serverTimeOffset").on("value", (snapshot) => { serverTimeOffset = snapshot.val() });
ref.on("value", (snapshot) => {
const seconds = snapshot.val().seconds;
const startAt = snapshot.val().startAt;
const interval = setInterval(() => {
...
}, 100)
});
Then every timer our interval expires, we're going to calculate the time that is left:
const serverTimeOffset = 0;
database.ref(".info/serverTimeOffset").on("value", (snapshot) => { serverTimeOffset = snapshot.val() });
ref.on("value", (snapshot) => {
const seconds = snapshot.val().seconds;
const startAt = snapshot.val().startAt;
const interval = setInterval(() => {
const timeLeft = (seconds * 1000) - (Date.now() - startAt - serverTimeOffset);
...
}, 100)
});
And then finally we log the remaining time, in a reasonable format and stop the timer if it has expired:
const serverTimeOffset = 0;
database.ref(".info/serverTimeOffset").on("value", (snapshot) => { serverTimeOffset = snapshot.val() });
ref.on("value", (snapshot) => {
const seconds = snapshot.val().seconds;
const startAt = snapshot.val().startAt;
const interval = setInterval(() => {
const timeLeft = (seconds * 1000) - (Date.now() - startAt - serverTimeOffset);
if (timeLeft < 0) {
clearInterval(interval);
console.log("0.0 left)";
}
else {
console.log(`${Math.floor(timeLeft/1000)}.${timeLeft % 1000}`);
}
}, 100)
});
There's definitely some cleanup left to do in the above code, for example when a new countdown starts while one is still in progress, but the overall approach works well and scales easily to thousands of users.
I have problem on server side (node.js) with setInterval.
I want to check something every day at specific time and I set interval like this:
let maintainTime = backFunc.getNextMaintainTime(new Date());
let maintain = setInterval(() => {
let currentTime = new Date();
if (currentTime.getTime() > maintainTime.getTime()) {
maintainTime = backFunc.getNextMaintainTime(maintainTime);
//do the maintain
}
}, 360000);
//360000 to check on every hour
and here is my getNextMaintainTime function:
getNextMaintainTime: (maintainTime) => {
maintainTime.setDate(maintainTime.getDate() + 1);
maintainTime.setHours(4);
maintainTime.setMinutes(0);
maintainTime.setSeconds(0);
maintainTime.setMilliseconds(0);
return maintainTime;
}
When I test it out it works perfectly but when I start server on production every time it calls this function 2 times instead of 1 time at 4am, what could cause the problem?
I am trying to create a https function in google cloud functions that when called will make copies of a document in a Firebase database add an ID and timestamp to the copy and save it to a collection in Firestore. This function will repeat for a certain amount of time for a given interval. For example it if told to run for 2 minutes making a copy every 10 seconds, it will make 12 unique copies saved to Firestore when it is finished running.
Now I have already implemented this function for each specific document in the Firebase database. However this is not scalable. If I were to eventually have 1000 documents in the database then I would need 1000 unique functions. So I want a single https function that will make a copy of every document in the database add the unique id and time stamp to the copy before saving it to Firestore at its unique path.
Here is an example of what I have.
// Duration of function runtime in minutes
var duration = 2;
// interval in which the funtion will be called in seconds
var interval = 10;
// Make a Copy of doc 113882052 with the selected duration, interval, and runtime options
exports.makeCopy_113882052 = functions.runWith(runtimeOpts).https.onRequest((request, response) => {
var set_duration = 0; // Counter for each iteration of runEveryXSeconds
var functId = setInterval(runEveryXSeconds, (interval * 1000) ); //runEveryXSeconds will run every interval in milliseconds
// runEveryXSeconds will based on the desired parameters
function runEveryXSeconds() {
// If runEveryXSeconds has reached its last iteration clear functID so that it stops running after one last iteration
if(set_duration >= ((duration * 60 / interval) - 1)) {
console.log("have made ",((duration * 60 / interval) - 1)," copies will now exit after one last copy");
clearInterval(functId);
}
set_duration++; // Increment set_duration at the beginning of every loop
console.log("Add a charger every ", interval, " seconds until ", duration, " min is up! currently on iteration ", set_duration);
// grab a snapshot of the database and add it to firestore
admin.database().ref('/113882052').once('value').then(snapshot => {
var data = snapshot.val(); // make a copy of the snapshot
data.station_id = "113882052"; // add the station id to the copy
data.timestamp = admin.firestore.FieldValue.serverTimestamp(); // add the current server timestamp to the copy
admin.firestore().collection('copies/113882052/snapShots').add(data); // add the copy to firestore at the given path
// only return promis when all iterations are complete
if (set_duration >= (duration * 60 / interval)) {
console.log("return successfully");
response.status(200).send('Success'); // send success code if completed successfully
}
return null;
}).catch(error => {
console.log('error at promise');
response.send(error); // send error code if there was an error
return null;
});
} // End of runEveryXSeconds
}); // End of makeCopy_113882052
So this function here makes a copy of doc 113882052 from Firebase adds the station_id "113882052" and the currant time stamp to the copy and saves it to Firestore collection at the path "copies/113882052/snapShots". It does this 12 times.
All of the other docs and their associated functions work the same way, just swap out the 9 digits for a different 9.
My initial though process is to use wildcards, but those are only used with triggers like onCreate and onUpdate. I am not using these, I am using once(), so I am not sure this is possible.
I have tried swapping out the once() method with onUpdate() like so
functions.database.ref('/{charger_id}').onUpdate((change, context) => {
const before_data = change.before.val();
const after_data = change.after.val();
//const keys = Object.keys(after_data);
var data = change.after.val();
var sta_id = context.params.charger_id;
data.station_id = sta_id; // add the station id to the copy
data.timestamp = admin.firestore.FieldValue.serverTimestamp(); // add the current server timestamp to the copy
admin.firestore().collection('chargers/', sta_id, '/snapShots').add(data); // add the copy to firestore at the given path
// only return promise when all iterations are complete
if (set_duration >= (duration * 60 / interval)) {
console.log("return successfully");
response.status(200).send('Success'); // send success code if completed successfully
}
return null;
});
but it does not work. I believe it does not work because it would only make a copy if the doc was updated just as the function was called, but I am not sure.
Is there a way to use wild cards to achieve what I want, and is there another way to do this without wildcards?
Thanks!
If you want to make a copy of all nodes in the Realtime Database, you'll need to read the root node of the database.
So instead of admin.database().ref('/113882052'), you'd start with admin.database().ref(). Then in the callback/completion handler, you loop over the children of the snapshot:
admin.database().ref().once('value').then(rootSnapshot => {
rootSnapshot.forEach(snapshot => {
var data = snapshot.val(); // make a copy of the snapshot
data.station_id = snapshot.key; // add the station id to the copy
data.timestamp = admin.firestore.FieldValue.serverTimestamp(); // add the current server timestamp to the copy
...
})
I have a simple function in Cloud Functions that is triggered when any update occurs on my "clients" location in my Cloud Firestore database.
Problem is when I update the data once it changes the lastUpdated child of the document that was updated to seconds 1572841408099 and then I change the child again, it always reverts lastUpdated to a Cloud Firestore Timestamp that is for the time: "November 3, 2019 at 9:44:16 PM UTC-6" regardless of what time it actually is.
How do I get the following code to reliably return what time the data was updated?
import * as functions from 'firebase-functions';
export const clientUpdatedTask = functions.firestore.document('clients/{clientId}').onUpdate((change: any, context: any) => {
const before = change.before.data();
const after = change.after.data();
const timeEdited = Date.now();
if(before.lastUpdated.seconds !== after.lastUpdated.seconds) {
return 'The Time Did Not Change. No Need To Run Update!';
} else {
return change.after.ref.update({'lastUpdated' : timeEdited}, {merge: true});
}
});
Why does it revert back to a regular timestamp for a time in the past upon a second implication? Furthermore, why does it jump between the seconds and the timestamp on each update?