title: Voting on items - how to design database/aws-lambda to minimize AWS costs
body: <p>I'm working on a website that mostly displays items created by registered users. So I'd say 95% of API calls are to read a single item and 5% are to store a single item. System is designed with AWS API Gateway that calls AWS Lambda function which manipulates data in DynamoDB.</p>
  
  <p>My next step is to implement voting system (upvote/downvote) with basic fetaures:</p>
  
  <ul>
  <li>Each registered user can vote only once per item, and later is only allowed to change that vote.</li>
  <li>number of votes needs to be displayed to all users next to every item.</li>
  <li>items have only single-item views, and are (almost) never displayed in a list view.</li>
  <li>only list view I need is "top 100 items by votes" but it is ok to calculate this once per day and serve cached version</li>
  </ul>
  
  <p>My goal is to design a database/lambda to minimize costs of AWS. It's easy to make the logic work but I'm not sure if my solution is the optimal one:</p>
  
  <ul>
  <li>My <code>items</code> table currently has hashkey <code>slug</code> and sortkey <code>version</code></li>
  <li>I created <code>items-votes</code> table with hashkey <code>slug</code> and sortkey <code>user</code> and also <code>voted</code> field (containing -1 or 1)</li>
  <li>I added field <code>votes</code> to <code>items</code> table</li>
  <li>API call to upvote/downvote inserts to <code>item-votes</code> table but before checks constraints that user has not already voted that way. Then in second query updates <code>items</code> table with updated votes count. (so 1 API call and 2 db queries)</li>
  <li>old API call to show an item stays the same but grabs new <code>votes</code> count too (1 API call and 1 db query)</li>
  </ul>
  
  <p>I was wondering if this can be done even better with avoiding new <code>items-votes</code> table and storing user votes inside <code>items</code> table? It looks like it is possible to save one query that way, and half the lambda execution time but I'm worried it might make that table too big/complex. Each <code>user</code> field is a 10 chars user ID so if item gets thousands of votes I'm not sure how Lambda/DynamoDB will behave compared to original solution.</p>
  
  <p>I don't expect thousands of votes any time soon, but it is not impossible to happen to a few items and I'd like to avoid situation where I need to migrate to different solution in the near future.</p>