Search code examples
javascriptparse-platformrating-system

5-star rating system with four attributes


I couldn't find any implementation of this one.

I need to do a rating system using Parse.com where each object have four attributes that can be ranked from 1 to 5. What I know is that I would have to have a seperate class for that. What I've made up to this point is how table's column could look like:
objectId - in Parse every object has it
attr1 - (int) attribute no 1
attr2 - (int) attribute no 2
attr3- (int) attribute no 3
attr4- (int) attribute no 4
objectPointer - a Pointer to rated object
votesSum - (double) sum of votes

It would work like that: each rate is added to existing rate and when someone wants to know what's the rating of specific object then sum of each attribute is divided by votesSum. Of course there are other problem: - how to keep same users from rating on and on the same object? (Array maybe?) - how to let users modify their rating (that's bigger problem)

I'm looking for really simple concept here. Maybe You have faced that problem before.


Solution

  • Both problems are solvable by including a pointer to the user on the rating object. Multiples can be disallowed on beforeSave, which would try to find an existing rating with the same objectPointer and the same userPointer (the new column).

    And, upon finding that existing rating, beforeSave could either return an error, or -- even better -- just modify that existing rating, which is how the app would allow users to modify their rating.

    For a system where there are thousands of ratings. It might also make sense to keep a ratings total object.

    So to summarize:

    Rating object:
        objectPointer - pointer to object being rating
        userPointer - pointer to the user doing the rating
        attr1 - (int) rating for the objects attr1
        attr2 - etc
        (no sum here)
    
    RatingTotal object:
        objectPointer - pointer to object being rating
        ratingsCount  - (int) total rating objects that exist for this objectPointer
        totalAttr1 - (int) sum of rating objects attr1
        totalAttr2 - etc
    
    
    Parse.Cloud.beforeSave("Rating", function(request, response) {
        // find out if there's an existing rating object
        var query = new Parse.Query("Rating");
        query.equalTo("objectPointer", request.object.objectPointer);     
        query.equalTo("userPointer", request.object.userPointer);
        query.find().then(function(result) {
            // one exists?  just delete it, and this save will replace it
            return (result)? result.destroy() : null;
        }).then(function() {
            // update the summary object
            var query = new Parse.Query("RatingTotal");
            query.equalTo("objectPointer", request.object.objectPointer);
            return query.find();     
        }).then(function(result) {
            var RatingTotal = Parse.Object.extend("RatingTotal");
            // create one if it doesn't exist
            var ratingTotal = (result)? result : new RatingTotal();
            ratingTotal.set("ratingsCount", 1+ratingTotal.get("ratingsCount"));
            var attr1 = request.object.get("attr1");
            ratingTotal.set("totalAttr1", attr1+ratingTotal.get("totalAttr1"));
            // and so on for attrs 2, 3, etc
            return ratingTotal.save();
        }).then(function() {
            response.success();
        }, function(error) {
            response.error(error);
        });
    });
    

    Notice how, if we find an existing Rating object where the same user is rating the same object, then we just delete the existing one. Since we're doing this on a beforeSave, the new one will be saved ... effectively and edit of the original.