I am using Parse as my backend and Stripe as my payment API. Stripe unfortunately does not have the coupon functionality that I need, so I am implementing that myself on Parse.
I have a Coupons object for each user that has an array of all of the Coupon objects that a user has redeemed. When they request service through my app, I'd like it to pop the highest value Coupon from that array.
My current solution is horribly inefficient and not dynamic, with separate arrays for each of three values of coupons, and I check each array to see if it's empty before either moving on to the next one or popping off one of the Coupon objects.
I'd like to minimize the number of requests this uses so that it scales a bit better.
I have to fetch the Coupons object, so my first thought was to somehow include the array of coupons in that fetch, kind of like the include() method of a query. However, I don't see that functionality with fetch. As I type this, I'm remembering that you can use query.find() to fetch a specific object, so I'm going to try to do that rather than setting the objectId and calling fetch, and using the .include() method. Does this use extra requests for each object of my coupon array, or does it use one request for the query? Can I even .include() a property that is an array of pointers? If I do this, I'll just have to iterate through the coupons to figure out which one has the largest value, and remove that one from the array.
Another idea was to keep the array sorted at the time that I add coupons to it, so I'll always be able to pop off the first coupon and only fetch that one, rather than iterate through all of them. However, this will require me to fetch all coupons in the array at the time I add a coupon, so if including the array in the query does not use extra requests, it will actually be the more efficient option in terms of request usage.
My third thought that I was looking into involves performing a query based on the coupon array and sort in descending order by the value key. However, I'm not sure how to set up that query. Would it be query.containedIn("objectId", couponArray)
, where couponArray
is an array of pointers to Coupon objects and the query
is a query for Coupon objects? Then I can use query.first()
to get the objects, and I believe that the query will only use one request.
If you have some advice going forward, I'd greatly appreciate it. I also apologize if this kind of question is kind of against policy, since I'm asking for advice on how to start implementing something rather than advice on how to fix something I was implementing.
Thanks for reading,
Jake
I'd stay away from arrays entirely in this case. There's no need to complicate the queries or the data model with arrays.
Have a separate Coupon
object for each and include a User
pointer to whoever it is applicable. Then all you have to do is query for all of the coupons which point to a User, sort by descending, and you're set. If there is a coupon, it will be the largest one first.
One downside to this approach could be creating a large number of Coupon
objects, but that's pretty irrelevant. Parse is very good about managing their databases and properly sharding/segmenting it for good performance. To limit the number of coupons active at a given time you could also add an expiration date to each coupon, and then use a cloud background job to periodically clean up expired coupons.
As a general rule of thumb, it's much better to focus on building the best possible user experience than to focus too much on scalability. By and large, issues of scalability rarely come into play because most apps fail. Not saying that to be discouraging; just something to keep in mind and prevent you from falling into the trap of over-engineering at the cost of time :)