0

I have a class called Stats which contains the columns secondsPlayed (number), createdAt (date) and timeScore (number)

This class contains thousands of objects but the timeScore column is empty.

I want to populate the timeScore column with a formula using the columns secondsPlayed (number), createdAt (date) like you would do in Excel. The formula is:

(secondsPlayed*10^8)/(Date.now()-createdAt.getTime())

As you can see the values of the timeScore column should change every second since Date.now() and secondsPlayed are variables that are constantly changing.

Because of this I want to update and repopulate the timeScore column every 5 minutes. This should happen automatically.

What is the best way to do this? I figured using cloud code to compute and populate the timeScore column and then just get the timeScore list with a simple Parse query would be best compared to downloading thousands of objects to each device and computing and updating every 5 minutes client side.

I dont know much about writing cloud code but by reading this guide and this SO question I came up with the following code.

const _ = require("underscore");
Parse.Cloud.define("timeScore", function(request, response) {
  const query = new Parse.Query("Stats");
  const maxSeconds = (Date.now() - new Date('2017-12-12T06:00:04.022Z').getTime())/1000;
  query.lessThan("secondsPlayed", maxSeconds);
  query.find().then(function(results) => {
        _.each(results, function(result) {
            var secondsPlayed = result.get("secondsPlayed") || 0;
            var createdAt = result.get("createdAt") || new Date('2017-12-12T06:00:04.022Z');
            result.set("timeScore", (secondsPlayed*100000000)/(Date.now()-createdAt.getTime()));
      });
        return Parse.Object.saveAll(results);
    }).then(function(results) {
        response.success(results);
    }, function(error) {
        response.error(error);
    })
    .catch(() =>  {
      response.error("FAILED");
    });
});

I do not know what to do with this code. I dont know how to test it or if it even works. How should I proceed?

Do I need to call it from the xamarin app? I just need the column to be populated and updated every 5 minutes according to the code. I should not need to call the cloud code from the app. I just want to query the timeScore column from the app. Is this possible?

Murat Kaya
  • 193
  • 1
  • 18

1 Answers1

0

To test from a .net client, ParseCloud provides CallFunctionAsync. See the guide for an example here.

At least one problem you'll find with the code is that query will return 1k objects maximum, so the query/update/save logic will have to cursor through the Stats objects each time this runs.

Once tested, you'll need to create a web worker which Heroku will let you schedule. See their guide about that here.

But I'm reluctant to go into further detail on any of these points, because I disagree with a premise of the question: that this update should be done, or done recurrently.

Consider that running this code adds no new information to the system. The createdAt field remains fixed. All that this code does is produce a strange way of representing the current time (as a createdAt time and an interval since then) thousands of times per run. This is exactly the sort of thing that should be done only when that interval (now - createdAt) needs to be known for a given object.

danh
  • 62,181
  • 10
  • 95
  • 136
  • Hi, thank you for the answer. I do not see why I need to test or run the code from client side. I just want to populate column C using the columns A and B. I am not returning data to the client and what I am doing has nothing to do with the client. Is there anyway to run the code without calling it from a client? I actually dont need to query as I do want every row of column C to be populated. So I need to run the code on every object. Would I still have the 1k problem? – Murat Kaya Jun 06 '18 at 21:23
  • What I am calculating is a score like you would have in a game. If the user is not playing (secondsPlayed) is not changing but time is passing (Date.now()-createdAt.getTime()) the users score will decrease. I need to update the users score every 5 minutes. – Murat Kaya Jun 06 '18 at 21:23
  • How and when does the user see her score? That's my opinion about where and when you would do this calculation. Consider this: if the server side job runs every five minutes, at any given moment, everyone's scores are wrong by an average of 2.5 minutes. – danh Jun 06 '18 at 23:20
  • Sorry, BTW, for mixup about calling from a client. I misunderstood the line "Do I need to call it from the xamarin app?" as a question about how to call it from a .NET client. You could just host and use a cron to make a recurring call. Heroku's version of that is a "scheduled worker". As for running it without a client/user eventually getting the result, see https://en.wikipedia.org/wiki/If_a_tree_falls_in_a_forest – danh Jun 06 '18 at 23:25
  • Hi, user will see their score everytime they open the high scores screen. If I could populate the column C server side the client would see the data with a simple parse query that will show top 100 values of column C. The scores are rounded up to the nearest integer so 5 minutes does not actually affect the score since (Date.now()-createdAt.getTime()) can be months or even years. There is no point in running the code every second. But if it wont have any negative effects I may do it. – Murat Kaya Jun 07 '18 at 11:37
  • So opening the high score screen is when this calculation matters, and no place else. Imagine running it every five mins for an hour when nobody looks at high scores. All those runs in that hour were just wasted electricity. Even the last run is a little off because it might be 5 mins old. I understand that the resolution on time that you care about is low, but that's reason to run it *less* often, not more. – danh Jun 07 '18 at 20:24
  • So the right computing question to ask is: what's the *least often* we can run it and get the *most correct* result. The answer is: when the high score query is done, just before we show results to the user. Hope I've made my POV clear. Best of luck! – danh Jun 07 '18 at 20:24
  • Hi I see your point. But imagine if I have hundreds of users and each of them opens the high scores screen one after the other with a second in between. In this case the cloud code could run hundreds of times in 5 minutes instead of only once. I have managed to make the Heroku Scheduler work. But the simple version wont allow me to run the cloud code more than once every 10 minutes which is good enough for my needs. – Murat Kaya Jun 22 '18 at 16:02
  • Hi I am accepting this answer as heroku schedular was what I needed. Can you take a look at this question? I have a small issue with my code. https://stackoverflow.com/questions/50991523/updating-and-saving-thousands-of-objects-at-once-on-parse-server-using-cloud-cod – Murat Kaya Jun 27 '18 at 08:14