title: Guidelines for creating GSI in DynamoDB
body: <p>Imagine that you need to persist something that can be represented with following schema:</p>
  
  <pre><code>{
    type: String
    createdDate: String (ISO-8601 date)
    userId: Number
    data: {
      reference: Number,
      ...
    }
  }
  </code></pre>
  
  <p><code>type</code> and <code>createdDate</code> are always defined/required, everything else such as <code>userId</code>, <code>data</code> and whatever fields within <code>data</code> are optional. Combination of <code>type</code> and <code>createdDate</code> does not guarantee any uniqueness. Number of fields within data (when <code>data</code> exists) may differ.</p>
  
  <p>Now imagine that you need to query against this structure like:</p>
  
  <ol>
  <li>Give me items where <code>type</code> is equal to something</li>
  <li>Give me items where <code>userId</code> is equal to something</li>
  <li>Give me items where <code>type</code> AND <code>userId</code> are equal to something</li>
  <li>Give me items where <code>userId</code> AND <code>data.reference</code> are equal to something</li>
  <li>Give me items where <code>userId</code> is equal to something, where <code>type</code> IS IN range of values and where <code>data.reference</code> is equal to something</li>
  </ol>
  
  <p>As it seems to me HashKey needs to be introduced on table level to uniquely match the item. Only choice that i have is to use something like UUID generator. Based on that i can't query anything from table that i need described above. <em>So i need to create several global secondary indexes to cover all fifth cases above as follows:</em></p>
  
  <ol>
  <li>For first use case i could create GSI where <code>type</code> can be HashKey and <code>createdDate</code> can be RangeKey.What bothers me from start here as i mentioned, there is high chance for this composite key to NOT be unique.</li>
  <li>For second use case i could crate GSI where <code>userId</code> can be HashKey and <code>createdDate</code> can be RangeKey
  Here probably this composite key can match item uniquely.</li>
  <li>For third use case, i have probably two solutions. Either to create third GSI where <code>type</code> can be HashKey and <code>userId</code> can be RangeKey. With that approach i'm losing ability to sort returned data and again same worries, this composite key does not guarantee uniqueness. Another approach would be to use one of two previous GSIs and using FilterExpression, right?</li>
  <li>For fourth use case i have only one option. To use previous GSI with <code>userId</code> as HashKey and <code>createdDate</code> as a RangeKey and to use FilterExpression against <code>data.reference</code>. Index can't be created on fields from nested object <strong>right?</strong></li>
  <li>For fifth use case, because IN operator is only supported via FilterExpression (<strong>right?</strong>) only option again is to use GSI with <code>userId</code> as HashKey and <code>createdDate</code> as a RangeKey and to use FilterExpression for both <code>type</code> and <code>data.reference</code>?</li>
  </ol>
  
  <p>So as only bright side of this problem i see using GSI with <code>userId</code> as HashKey and <code>createdDate</code> as RangeKey. <strong>But again userId is not mandatory field it can be NULL. HashKey can't be NULL right?</strong></p>
  
  <p><strong>Most importantly</strong>, if composite key(HashKey and RangeKey) can't guarantee uniqueness that means that saving item with composite key that already exists in index will silently rewrite previous item which means i will lose the data?</p>