# Table Indexing

When it comes to indexing your tables, you have to be mindful of which data you'll need to access quickly/frequently within your contract. Less frequently accessed data can be handed using an off-chain indexer, or even a simple API call if you aren't storing tons of rows in your tables.

There are several options here, I'll outline the most common approaches below.

### available\_primary\_key

This is the most straightforward of all. This method will just use the next available key, based on the highest value currently stored in your table. For example...

```cpp
struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] balances {
	uint64_t 	id;
	eosio::name  	wallet;
	eosio::asset 	balance;
  
  uint64_t primary_key() const { return id; }
};
using balances_table = eosio::multi_index< "balances"_n, balances >;

ACTION createrow( const name& user, const asset& balance ){
	balances_table bal_t = balances_table( _self, _self.value );
	bal_t.emplace( user, [&](auto &_u){
		_u.id = bal_t.available_primary_key();
		_u.wallet = user;
		_u.balance = balance;
	});
}
```

### By User

Let's say you have a table, and you are 100% certain that each user in the table will only need 1 row. You can handle this simply by using the `user.value`

```cpp
struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] balances {
	eosio::name  	wallet;
	eosio::asset 	balance;
  
  uint64_t primary_key() const { return wallet.value; }
};
using balances_table = eosio::multi_index< "balances"_n, balances >;

ACTION someaction( const name& user ){
	require_auth( user );
	
	balances_table bal_t = balances_table( _self, _self.value );
	auto itr = bal_t.require_find( user.value, "you do not have a balance" );
}
```

### By uint128\_t Of 2 Values

Let's say for example, you have an NFT market contract. All of the drop purchases are stored in a single table, under the same scope. Each drop can contain multiple orders, and each user can have orders for multiple drops. Using the drop ID, or the user's wallet as a primary index will not work in this case. You can solve this using the following method.

```cpp
#define mix64to128(a, b) (uint128_t(a) << 64 | uint128_t(b))

struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] orders {

	uint64_t  	order_id;
	eosio::name 	wallet;
	uint64_t  	drop_id;			

	uint64_t primary_key() const { return order_id; }
	uint128_t secondary_key() const { return mix64to128( wallet.value, drop_id ); }
};
using orders_table = eosio::multi_index<"orders"_n, orders,
eosio::indexed_by<"userdropmix"_n, eosio::const_mem_fun<orders, uint128_t, &orders::secondary_key>>
>;

ACTION findorder( const name& wallet, const uint64_t& drop_id ){
	orders_table orders_t = orders_table( _self, _self.value );
	auto orders_secondary = orders_t.get_index<"userdropmix"_n>();
	
	uint128_t user_drop_key = mix64to128( wallet.value, drop_id );
	auto itr = orders_secondary.require_find( user_drop_key, "no match found for this user + drop" );
}
```

### By checksum256

Sometimes 128 bits is not enough to meet the needs for an index. For example, you may have a contract where you need to index by a combination of user, token and contract and be able to easily find that key. You can accomplish this by using a checksum256 hash, as demonstrated below.

{% code fullWidth="true" %}

```cpp
struct [[eosio::table, eosio::contract(CONTRACT_NAME)]] tokens {
	uint64_t  					id; 	// available_primary_key
	eosio::name  				user;
	eosio::extended_asset  		balance;

	uint64_t primary_key() const { return id; }

	// combine 3 values into a checksum256
	static eosio::checksum256 create_checksum(const uint64_t& a, const uint64_t& b, const uint64_t& c) {
		std::vector<char> data_stream(sizeof(uint64_t) * 3);
		eosio::datastream<char*> ds(data_stream.data(), data_stream.size());
		ds << a << b << c;

		auto result_hash = eosio::sha256(data_stream.data(), data_stream.size());
		return result_hash;
	}

	eosio::checksum256 by_user_token() const { return create_checksum( user.value, balance.quantity.symbol.code().raw(), balance.contract.value ); }

};
using tokens_table = eosio::multi_index<"tokens"_n, tokens,
      eosio::indexed_by<"userandtoken"_n, eosio::const_mem_fun<tokens, eosio::checksum256, &tokens::by_user_token>>
      >;

ACTION mycontract::dosomething(const name& user, const asset& quantity, const name& contract){
	tokens_table tokens_t = tokens_table( _self, _self.value );
	auto user_token_idx = tokens_t.get_index<"userandtoken"_n>();
	checksum256 user_token_key = tokens::create_checksum( user.value, quantity.symbol.code().raw(), contract.value );
	auto itr = user_token_idx.require_find( user_token_key, "could not locate user + token row" );
}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://waxdao.gitbook.io/wax-smart-contract-development-guide/tips-and-tricks/table-indexing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
