2

I have created a background job to run every minute. The purpose of it is to delete old or outdated data within the database. In this case, the user submits a time which has an attached timestamp to it, and the two values are stored in arrays times and timestamp. So I wrote my cloud code to check if the times are older than an hour via their timestamps. If so, delete them from the database. However, that's the part I'm having trouble with. Here's my cloud code so you can see what's going on:

Parse.Cloud.job("expireTimes", function(request, response){
Parse.Cloud.useMasterKey();
var currentTime = new Date().getTime() / 1000;
var query = new Parse.Query("Wait");
query.find().then(function(results) {
    var times = (results.length>0)? results[0].get("times") : "n/a";
    var timestamps = (results.length>0)? results[0].get("timestamp") : "n/a";
    console.log("Got " + results.length + " Times: " + times);
    console.log("Got " + results.length + " Timestamps: " + timestamps);
    for (var i = 0; i < timestamps.length; i++) {
        if (currentTime >= timestamps[i] + 3600) {
            // Delete old wait times
            timestamps.splice(i, 1);
            times.splice(i, 1);
            i--;
        } else {
            break;
        }
    };

    response.success("success");
}, function(error) {
    response.error(error);
});
})

How do I update the database and delete the values within the array. Because when a user submits the time, it just adds to the times array. Well, if I have the background job going every minute, some entries aren't going to be over an hour old. I want to keep those, but get rid of the other ones.

Any ideas? Any help is much appreciated. Thank you

bwc
  • 1,732
  • 1
  • 14
  • 27

2 Answers2

0

The essential part of the answer is that object properties can be set with set() and objects are saved with save(). Here's a quick example of just that...

    // say object is some object that's been retrieved from the database
    var times = object.get("times");
    var timestamps = object.get("timestamp");  // would be better to make the array name plural in the database

    // do whatever you want to the arrays here, then ...

    object.set("times", times);
    object.set("timestamp", timestamps);
    return results[0].save();
}).then(function(result) {
        response.success("success");
}, function(error) {
        response.error(error);
});

But I understand you really want to do this for many Wait objects, so we're going to need a stronger design. Let's start getting into the habit of building functions that do logical chunks of work. Here's one that fixes those arrays for a given Wait object...

// delete parts of the waitObject time arrays prior to currentTime
function removeOldWaitTimes(waitObject, currentTime) {
    var times = waitObject.get("times");
    var timestamps = waitObject.get("timestamp");
    for (var i = 0; i < timestamps.length; i++) {
        if (currentTime >= timestamps[i] + 3600) {
            // Delete old wait times
            timestamps.splice(i, 1);
            times.splice(i, 1);
            i--;
        } else {
            break;
        }
    };
    waitObject.set("times", times);
    waitObject.set("timestamp", timestamps);
}

We need to call this in a loop, for each Wait object found. When we're done, we need to save all of the objects that were changed...

Parse.Cloud.job("expireTimes", function(request, response){
    Parse.Cloud.useMasterKey();
    var currentTime = new Date().getTime() / 1000;
    var query = new Parse.Query("Wait");
    query.find().then(function(results) {
        for (var i=0; i<results.length; i++) {
            removeOldWaitTimes(results[i], currentTime);
        }
        return Parse.Object.saveAll(results);
    }).then(function(result) {
        response.success("success");
    }, function(error) {
        response.error(error);
    });
});

Please note that as the number of objects in the Wait class grows large, the job might get too long or the query (which can be set to a max limit of 1k objects returned) might miss results. We'll need to improve the query if that becomes a risk. (e.g. if the job runs every hour, there's no reason to retrieve Wait objects that were updated more than an hour ago).

EDIT say you want to update some as above, and destroy others. You'll need to handle two promises to do that...

Parse.Cloud.job("expireTimes", function(request, response){
    Parse.Cloud.useMasterKey();
    var destroyThese = [];
    var currentTime = new Date().getTime() / 1000;
    var query = new Parse.Query("Wait");
    query.find().then(function(results) {
        var updateThese = [];
        for (var i=0; i<results.length; i++) {
            var result = results[i];
            if (result.get("times").length > 0) {
                removeOldWaitTimes(result, currentTime);
                updateThese.push(result);
            } else {
                destroyThese.push(result);
            }
        }
        return Parse.Object.saveAll(updateThese);
    }).then(function(result) {
        return Parse.Object.destroyAll(destroyThese);
    }).then(function(result) {
        response.success("success");
    }, function(error) {
        response.error(error);
    });
});

We place destroyThese array in the enclosing scope so that it is available to the next step in the chain of promises.

danh
  • 62,181
  • 10
  • 95
  • 136
  • Thank you so much for doing this for me. I really appreciate it so much. Is there a way that we can check in the delete function if the array is empty to just delete the whole object? Or should I create another background function that just checks if the `times` array is empty and if so, delete the whole object? – bwc Nov 27 '15 at 21:36
  • You may also delete a batch at a time with destroyAll(), but these will be two asynch operations, and we'll need a little more sophistication to do that properly. I'll try to answer in an edit... – danh Nov 27 '15 at 21:39
  • Okay, thank you so much! This has helped me so much! – bwc Nov 27 '15 at 21:41
  • A quick peek at the [docs](https://parse.com/docs/js/api/classes/Parse.Object.html#methods_saveAll) says that `Parse.Object.saveAll` does not return a promise... (they may be outdated) quickfix : https://gist.github.com/hhanesand/b809d6f1d438174e2d91 – hhanesand Nov 30 '15 at 09:47
  • @lightice11 - saveAll() returns a promise. Error of omission in the docs. The gist looks right but unnecessary. – danh Nov 30 '15 at 14:52
  • Cool. Had a feeling that was the case. – hhanesand Nov 30 '15 at 15:17
0

Currently, i didn't find the best solution, but it's working for me now.

var Progress = Parse.Object.extend(PROGRESS);
var progressQuery = new Parse.Query(Progress);
progressQuery.equalTo("userId", userId)
progressQuery.find({
    success: function (progress){
        for (i = 0; i < progress.length; i++){
            progress[i].set("lastUse", false)
            progress[i].save()
        }

    },
    error: function(object, error) {
        console.log(error)
    }
})
Tuan Nguyen
  • 2,542
  • 19
  • 29