Meteor delete database record at specific time

So I made simple meteor API (server side). My client (Android user) can reserve charging station (basically record in reservations collection). What I want to to is : if user is late for charging (at least 15 min.) I need to delete that reservation (or record) from database. So question is it possible to do that in meteor?

So here’s the example: User reserves station at 10:00 so if user is not charging after 10:15 reservation should be deleted.

There are some ways. The most simple is to set a interval function of 1 minute to query the database for reservations without charge that are older then 15 minutes and remove them or mark them as removed:

Meteor.setInterval(() => {
    Reservations.remove({
        createdAt: {
            $lte: moment().subtract(15,'minutes'.toDate()
        },
        isCharged: false
    });
});

Thanks, however I end up with this solution

queryResult = Collections.Reservation.insert(insertData, function(err, _id){
            if(_id != null) {
               
                Meteor.setTimeout(function(){
                    console.log("istrinta rezervacija su id " + _id);
                    Collections.Reservation.remove(_id);
                }, timeDiff);
            }
        });

However I don’t know about perfomance of setTimeout, is there are any other alternatives?

If it’s only going to be for 15 minutes, your solution is probably the most performance friendly I would think. I guess you could run out of memory by having a million setTimeouts waiting, but they’re probably pretty lightweight I would think. Cloudspider’s solution is also fine.

That solution is only just okay for a single server instance, but is likely to cause trouble if you have multiple instances. Especially so in a containerised deployment (like Galaxy) where containers may be migrated and thus lose state - the setTimeout in your case would no longer exist.

A much safer solution would be to use either percolate:synced-cron or vsivsi:job-collection, both of which are multi-server and migration safe.

2 Likes

Good point! I was feeling a little uneasy about setTimeout. And even if you don’t get to that size, you’re going to have annoying issues during development when you’re testing and restarting all the time. I think Cloudspider’s solution is still okay though. You should put isCharged at the top though and add an index for it, so that Mongo doesn’t search through your entire reservation history.

You should put isCharged at the top though and add an index for it, so that Mongo doesn’t search through your entire reservation history.

True indeed. I’ve typed that on my phone and left it out of scope. Read loads are fine, but keep an eye out o the queries :slight_smile:

A much safer solution would be to use either percolate:synced-cron or vsivsi:job-collection, both of which are multi-server and migration safe.

I like synced cron. Its a bit simpeler then vsivsi. For complex processing though I would prefer the vsivsi package.

1 Like

Since I’m not familiar with your end goal, I have questions as much as solutions, but that said…

If you are simply trying to allow another user to reserve the station after the first reservation is expired, it would seem easier to set a reservation_expires date/time on the document, and then check whether that time has passed if another user tries to reserve or use that station. If it has expired allow the use or reservation, if not, then don’t.

Perhaps I’m missing why you need an actual timer on this.

1 Like

Or you could just use mongdbs time to live index, which removes documents automatically based on a timestamp in the docoument.
https://docs.mongodb.com/v3.2/core/index-ttl/

That will affect all documents in the collection - not just those with an expired time.

If a document does not contain the indexed field, the document will not expire.

https://docs.mongodb.com/v3.2/core/index-ttl/#expiration-of-data

So this could do the trick:

db.reservations.createIndex( { "expiresAt": 1 }, { expireAfterSeconds: 15 * 60 } )

It won’t affect documents without the indexed field. So if you remove the field once the user starts charging al should be fine.

I’m not saying this is the best solution (because you might want a more flexible approach for when stuff expires), but it’s doable.

1 Like

Thank You for the answer! But how can I remove that field? Did you mean index?

Haven’t used expiration myself but I assume he meant you just remove it with $unset{expireAfterSeconds:true}.

1 Like

That would notify a user only after he/she applied a action. Which to me sounds like a bad user experience. Preventing a user to try the action is much more friendly. For example disabling a form or button or showing a state.

But then again. I agree that its not really clear what the end goal is

Thanks for chiming in. That’s exactly what I meant, but you should remove the expiresAt from the document and it shouldn’t be automatically removed anymore.

So expiresAt is the attribute on the document (Date).
expireAfterSeconds is part of the index on the collection (Integer).

1 Like