Using Reviews to Rate Products and Channels
Rating value
Let's assume the rating interface is using a system with 5 stars. The rating
field of a review is a number between -100 and 100.
We first have to know how to encode the number of stars in the rating
field.
Number of stars | Rating value |
---|---|
★★★★★ | 5 |
★★★★☆ | 4 |
★★★☆☆ | 3 |
★★☆☆☆ | 2 |
★☆☆☆☆ | 1 |
☆☆☆☆☆ | 0 |
Here, we use the rating
field to represent the number of stars.
We could also use this field to store a percentage (ex: 95
would mean 95 %), or to store a like/dislike information (1
would mean like, -1
would mean dislike).
Review approval process
If you do not need any approval process, skip this part
If we have an approval process for a review to be used for a product or a channel, we model the approval process with a state machine.
First of all, we create the approved
state:
POST /<project-key>/states
with:
{"key": "approved","type": "ReviewState","roles": ["ReviewIncludedInStatistics"]}
Then we create the initial pending-approval
state, which has a possible transition to the approved
state:
POST /<project-key>/states
with:
{"key": "pending-approval","type": "ReviewState","initial": true,"transitions": [{"typeId": "state","id": "<id-of-approved-state>"}]}
Creating Reviews
Now we can create a review in the initial state pending-approval
:
POST /<project-key>/reviews
with:
{"key": "review-1","target": {"typeId": "product","id": "<product-id>"},"rating": 4,"state": {"key": "pending-approval"}}
remove the field state
if you have not created any state machine first
Query which Reviews should be approved
skip this part if you do not have any approval process
We can query which reviews should be approved with a where predicate
GET /<project-key>/reviews
with query parameters:
where=state(id in ("<id-of-pending-approval-state>"))
final ReviewPagedQueryResponse reviewPagedQueryResponse = apiRoot.reviews().get().withWhere("state(id in (\"<id-of-pending-approval-state>\"))").executeBlocking().getBody();
Approving a Review
skip this part if you do not have any approval process
We can now approve the review review-1
:
POST /<project-key>/reviews/key=review-1
with:
{"version": 1,"actions": [{"action": "transitionState","state": {"key": "approved"}}]}
Displaying Products
We can display all products:
- that have at least 3 stars (average rating superior to 3)
- with facets about the number of products rated with an average in the different ranges 0 to 1 star, 1 to 2 stars, 2 to 3 stars, 3 to 4 stars and 4 to 5 stars.
- sorted by average ratings
For that, we use the search endpoint:
GET /<project-key>/product-projections/search
with query parameters:
filter = reviewRatingStatistics.averageRating:range (3 to *)
facet = reviewRatingStatistics.averageRating:range (0 to 1), (1 to 2), (2 to 3), (3 to 4), (4 to 5)
sort = reviewRatingStatistics.averageRating desc
ProductProjectionPagedSearchResponse productSearchWithFilterResult = apiRoot.productProjections().search().get().withFilter("reviewRatingStatistics.averageRating:range (3 to *)").withFacet("reviewRatingStatistics.averageRating:range (0 to 1), (1 to 2), (2 to 3), (3 to 4), (4 to 5)").withSort("reviewRatingStatistics.averageRating desc").executeBlocking().getBody();
The response gives us the following information:
{"offset": 0,"count": <number of products to display>,"total": <total number of products with an average rating superior to 3>,"results": [{"id": "<product-1-id>",[...]"reviewRatingStatistics": {"averageRating": 4.07037,"highestRating": 5,"lowestRating": 3,"count": 1009,"ratingsDistribution": {"5": 254,"4": 572,"3": 183}}},{"id": "<product-2-id>",[...]"reviewRatingStatistics": {"averageRating": 2.97677,"highestRating": 1,"lowestRating": 0.2,"count": 3875,"ratingsDistribution": {"4": 145,"3": 3495,"2": 235}}},[...]],"facets": {"reviewRatingStatistics.averageRating": {"type": "range","dataType": "number","ranges": [{"from": 0.0,"to": 1.0,"count": 0},{"from": 1.0,"to": 2.0,"count": 15},{"from": 2.0,"to": 3.0,"count": 78},{"from": 3.0,"to": 4.0,"count": 242},{"from": 4.0,"to": 5.0,"count": 145}]}}}
Displaying one Product
The following information can be found in the JSON data of one product:
- average rating:
reviewRatingStatistics.averageRating
.
The value is already rounded to 5 decimals. Depending on your need, you may have to round it more. - number of reviews:
reviewRatingStatistics.count
. - distribution of ratings:
reviewRatingStatistics.ratingsDistribution
:
★★★★★:reviewRatingStatistics.ratingsDistribution.5
★★★★☆:reviewRatingStatistics.ratingsDistribution.4
★★★☆☆:reviewRatingStatistics.ratingsDistribution.3
★★☆☆☆:reviewRatingStatistics.ratingsDistribution.2
★☆☆☆☆:reviewRatingStatistics.ratingsDistribution.1
☆☆☆☆☆:reviewRatingStatistics.ratingsDistribution.0
If one field for one rating does not exist, it means that there are no reviews with that rating value.
Displaying all Reviews of one Product
To retrieve all reviews for one product, sorted by rating:
GET /<project-key>/reviews
with query parameter:
where = target(typeId = "product" and id = "<product-id>")
sort = rating desc
final ReviewPagedQueryResponse review = apiRoot.reviews().get().withWhere("target(typeId = \"product\" and id = \"<product-id>\")").withSort("rating desc").executeBlocking().getBody();
To query only the reviews used for the rating statistics of the product:
GET <project-key>/reviews
with query parameters:
where = target(typeId = "product" and id = "<product-id>") and includedInStatistics = true
sort = rating desc
final Review reviewQuery = apiRoot.reviews().get().withWhere("target(typeId = \"product\" and id = \"<product-id>\") and includedInStatistics = true").withSort("rating desc").executeBlocking().getBody();