3

My goal is to delete all the message nodes 24 hours after they were sent using Firebase Cloud Functions and the Realtime Database. I tried copy and pasting the answer from this post however for some reason the messages delete directly after they were created rather than the 24 hours later. If someone could help me solve this problem I would really appreciate it. I have tried multiple different answers based on the same issue and they haven't worked for me.

Here is my index.js file:

'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

// Cut off time. Child nodes older than this will be deleted.
const CUT_OFF_TIME = 24 * 60 * 60 * 1000; // 2 Hours in milliseconds.


exports.deleteOldMessages = functions.database.ref('/Message/{chatRoomId}').onWrite(async (change) => {
const ref = change.after.ref.parent; // reference to the parent
const now = Date.now();
const cutoff = now - CUT_OFF_TIME;
const oldItemsQuery = ref.orderByChild('seconds').endAt(cutoff);
const snapshot = await oldItemsQuery.once('value');
// create a map with all children that need to be removed
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
});
// execute all updates in one go and return the result to end the function
return ref.update(updates);
});

And my database structure is: enter image description here

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Jaqueline
  • 465
  • 2
  • 8
  • 25
  • Many developers have reported problems implementing this, but like [here last week](https://stackoverflow.com/questions/56247938/cloud-function-deletes-node-instantly-instead-of-after-two-hours-based-off-times), the problem is always in a change they made. For example: what is the value of `cutoff` when you log it? How does that compare to the value of `seconds` in your JSON? – Frank van Puffelen May 27 '19 at 01:35
  • @FrankvanPuffelen I'm sorry to ask this question but what do you mean by logging it and how? The seconds that is stored is from the seconds since 1970 – Jaqueline May 27 '19 at 02:42
  • `console.log(cutoff)` and then check in the logging panel of your Cloud Functions. If you are new to JavaScript, Cloud Functions for Firebase is not the best way to learn it. I recommend first reading the [Firebase documentation for Web developers](https://firebase.google.com/docs/database/web/start). That covers many basic JavaScript, and Firebase Database interactions. You could also use the Admin SDK in a local Node.js process, which can be debugged with a local debugger. After those you'll be much better equipped to write code for Cloud Functions too. – Frank van Puffelen May 27 '19 at 03:12
  • @FrankvanPuffelen I apologize for the late response. I logged it and got 1559331549417 in the console. What should I do next? I appreciate your help with this – Jaqueline Jun 01 '19 at 19:46
  • `1559331549417` looks later than any values you shared with us. Essentially: compare the logged value with the values in your database, and see if they're indeed all older than that. If they are, the problem is in how you determine the `cutoff` value. – Frank van Puffelen Jun 01 '19 at 21:06
  • @FrankvanPuffelen I just tried sending another message and comparing the times. The time in the database is 1559426062 while the time for the logged value is 1559339672823. Could it be that the cutoff time is doing it in milliseconds or something? The time in the database is in Date().timeIntervalSince1970 in Swift – Jaqueline Jun 01 '19 at 21:59
  • That indeed looks like you're storing the time from the client in seconds, which is quite common from iOS. See my answer here: https://stackoverflow.com/questions/52600881/how-to-remove-a-child-node-after-a-certain-date-is-passed-in-firebase-cloud-func/52611778#52611778 – Frank van Puffelen Jun 01 '19 at 22:05
  • I want to delete nodes after the end of the day, no matter when they are created. How to approach this? – Stack May 29 '20 at 07:40
  • @DheerajMahra you might want to look into a cloud scheduler. That’s what I ended up doing in the end for my purpose, but I think you could make it the same for you. – Jaqueline May 29 '20 at 15:55
  • @Jaqueline cloud scheduler comes in blaze plan. :( – Stack May 29 '20 at 17:34
  • 1
    @DheerajMahra yes but you still get the spark plan to use the free limit. You can also set a payment limit. – Jaqueline May 29 '20 at 18:15
  • @Jaqueline NIce. Let me explore the plans. – Stack May 30 '20 at 12:07

1 Answers1

3

In the comments you indicated that you're using Swift. From that and the screenshot it turns out that you're storing the timestamp in seconds since 1970, while the code in your Cloud Functions assumes it is in milliseconds.

The simplest fix is:

// Cut off time. Child nodes older than this will be deleted.
const CUT_OFF_TIME = 24 * 60 * 60 * 1000; // 2 Hours in milliseconds.


exports.deleteOldMessages = functions.database.ref('/Message/{chatRoomId}').onWrite(async (change) => {
    const ref = change.after.ref.parent; // reference to the parent
    const now = Date.now();
    const cutoff = (now - CUT_OFF_TIME) / 1000; // convert to seconds
    const oldItemsQuery = ref.orderByChild('seconds').endAt(cutoff);
    const snapshot = await oldItemsQuery.once('value');
    // create a map with all children that need to be removed
    const updates = {};
    snapshot.forEach(child => {
        updates[child.key] = null;
    });
    // execute all updates in one go and return the result to end the function
    return ref.update(updates);
});

Also see my answer here: How to remove a child node after a certain date is passed in Firebase cloud functions?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I tried to do this and I still get the same response as before I don't understand. I also looked at the other answer but the function is done in an HTTP rather than onWrite – Jaqueline Jun 01 '19 at 23:17
  • How the function is triggered shouldn't make much of a difference, as long as you wire up `ref`. If it still doesn't work, do the same as before: log `cutoff` and compare it to the values in your database. – Frank van Puffelen Jun 01 '19 at 23:52
  • I tried all of that but for some reason I'm still getting the same result. I've also tried making the seconds in my database as milliseconds and use the original function and they still delete right away. Do you have any suggestions on how I can do this? It's right on the edge of working I feel like it just needs to be changed a tad. The values in the log are still the same as before. – Jaqueline Jun 08 '19 at 18:03
  • The problem in your original code was the seconds vs milliseconds comparison that I answered about. If you log the value of `cutoff` you can see what you're comparing the `seconds` value in the database to. If you tell us what it logs, we can help with that. – Frank van Puffelen Jun 08 '19 at 19:13
  • The seconds stored in the database is 1560021980 while the log of cutoff is 1560021905247. Thank you so much for helping me I really appreciate it! – Jaqueline Jun 08 '19 at 19:30
  • Ah, I now finally see what I forgot to show in my answer. Check the updated code. I highly recommend spending some time learning JavaScript through a tutorial, as trying to modify Cloud Functions like this is definitely not the easiest way to learn it. – Frank van Puffelen Jun 08 '19 at 19:34
  • I definetely agree! I just came upon Cloud Functions and found it perfect for what I'm trying to do rather than trying to do it on the user's side. This is very odd I'm getting the same results. It's taking longer for it to delete about 2 seconds later but it still deletes the messages right away. Could it be another factor? Here's the log 1560043238.927 and here is the database value 1560043316 – Jaqueline Jun 09 '19 at 01:27
  • do you have a suggestion for what I could do? – Jaqueline Jun 29 '19 at 12:30