When building scalable applications, especially in a SaaS (Software-as-a-Service) environment, multi-tenancy is a common architecture pattern. In a multi-tenant system, a single instance of an application serves multiple clients, ensuring data isolation for each tenant.
Amazon DynamoDB, a fully managed NoSQL database, is an excellent choice for such systems due to its ability to scale horizontally and its high availability. However, for a multi-tenant setup, the design of your data model is essential to ensure proper data isolation and performance.
In this article, we will demonstrate how to implement multi-tenancy in DynamoDB using Python and the boto3 SDK. We’ll create a single shared table, store data in a way that isolates tenants’ data, and interact with the data by adding users and orders for multiple tenants.
Table of Contents:
- What is Multi-Tenancy in DynamoDB?
- Designing DynamoDB for Multi-Tenancy
- Python Code to Implement Multi-Tenancy
- Creating the DynamoDB Table
- Conclusion
What is Multi-Tenancy in DynamoDB?
In a multi-tenant architecture, you need to logically partition the data to keep each tenant’s data isolated. This can be done using a single shared table and partitioning the data by a unique tenant identifier (tenant_id
).
For example, let’s say we have two tenants, Tenant A and Tenant B, each having users and orders. We can store the following in DynamoDB:
-
Tenant A’s data:
-
PK = tenant#tenantA
,SK = user#user1
-
PK = tenant#tenantA
,SK = order#order1
-
-
Tenant B’s data:
-
PK = tenant#tenantB
,SK = user#user2
-
PK = tenant#tenantB
,SK = order#order2
-
Each piece of data is associated with a PK
(Partition Key) representing the tenant, and the SK
(Sort Key) differentiates users from orders within that tenant.
This design ensures that each tenant’s data is logically isolated but stored in a shared table, which is more cost-effective and easier to manage.
Designing DynamoDB for Multi-Tenancy
To implement multi-tenancy, we’ll follow these design rules for the DynamoDB table:
- Partition Key (PK): Will include
tenant_id
, for example,tenant#tenantA
. - Sort Key (SK): Will differentiate between data types for each tenant, such as
user#user1
,order#order1
.
This design ensures that all data belonging to a particular tenant is grouped together under the same partition key but differentiated by the sort key. We can then query tenant-specific data by using the partition key (PK
) and apply further filtering based on the sort key (SK
).
Python Code to Implement Multi-Tenancy
Now that we have our design, let’s look at the Python code that will perform the following actions:
- Add Users: Add a user to a specific tenant.
- Add Orders: Add an order associated with a user.
- Retrieve Users: Retrieve a user by
tenant_id
anduser_id
. - Retrieve Orders for Tenant: Retrieve all orders for a given tenant.
We’ll use the boto3 library to interact with DynamoDB, so make sure it’s installed by running:
pip <span>install </span>boto3pip <span>install </span>boto3pip install boto3
Enter fullscreen mode Exit fullscreen mode
Full Python Code:
<span>import</span> <span>boto3</span><span>from</span> <span>uuid</span> <span>import</span> <span>uuid4</span><span>from</span> <span>boto3.dynamodb.conditions</span> <span>import</span> <span>Key</span><span>from</span> <span>decimal</span> <span>import</span> <span>Decimal</span><span># Initialize the DynamoDB resource </span><span>dynamodb</span> <span>=</span> <span>boto3</span><span>.</span><span>resource</span><span>(</span><span>'</span><span>dynamodb</span><span>'</span><span>)</span><span># Function to create the DynamoDB table </span><span>def</span> <span>create_table</span><span>():</span><span># Create the table if it doesn't exist </span> <span>try</span><span>:</span><span>table</span> <span>=</span> <span>dynamodb</span><span>.</span><span>create_table</span><span>(</span><span>TableName</span><span>=</span><span>'</span><span>MultiTenantTable</span><span>'</span><span>,</span><span>KeySchema</span><span>=</span><span>[</span><span>{</span><span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>PK</span><span>'</span><span>,</span><span>'</span><span>KeyType</span><span>'</span><span>:</span> <span>'</span><span>HASH</span><span>'</span> <span># Partition key </span> <span>},</span><span>{</span><span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>SK</span><span>'</span><span>,</span><span>'</span><span>KeyType</span><span>'</span><span>:</span> <span>'</span><span>RANGE</span><span>'</span> <span># Sort key </span> <span>}</span><span>],</span><span>AttributeDefinitions</span><span>=</span><span>[</span><span>{</span><span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>PK</span><span>'</span><span>,</span><span>'</span><span>AttributeType</span><span>'</span><span>:</span> <span>'</span><span>S</span><span>'</span><span>},</span><span>{</span><span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>SK</span><span>'</span><span>,</span><span>'</span><span>AttributeType</span><span>'</span><span>:</span> <span>'</span><span>S</span><span>'</span><span>}</span><span>],</span><span>ProvisionedThroughput</span><span>=</span><span>{</span><span>'</span><span>ReadCapacityUnits</span><span>'</span><span>:</span> <span>5</span><span>,</span><span>'</span><span>WriteCapacityUnits</span><span>'</span><span>:</span> <span>5</span><span>}</span><span>)</span><span>print</span><span>(</span><span>"</span><span>Creating table... Please wait until it</span><span>'</span><span>s created.</span><span>"</span><span>)</span><span>table</span><span>.</span><span>meta</span><span>.</span><span>client</span><span>.</span><span>get_waiter</span><span>(</span><span>'</span><span>table_exists</span><span>'</span><span>).</span><span>wait</span><span>(</span><span>TableName</span><span>=</span><span>'</span><span>MultiTenantTable</span><span>'</span><span>)</span><span>print</span><span>(</span><span>"</span><span>Table </span><span>'</span><span>MultiTenantTable</span><span>'</span><span> created successfully!</span><span>"</span><span>)</span><span>except</span> <span>Exception</span> <span>as</span> <span>e</span><span>:</span><span>print</span><span>(</span><span>f</span><span>"</span><span>Error creating table: </span><span>{</span><span>e</span><span>}</span><span>"</span><span>)</span><span># Initialize table after creation (if it does not exist) </span><span>create_table</span><span>()</span><span># Now, we can reference the table </span><span>table</span> <span>=</span> <span>dynamodb</span><span>.</span><span>Table</span><span>(</span><span>'</span><span>MultiTenantTable</span><span>'</span><span>)</span><span>def</span> <span>add_user</span><span>(</span><span>tenant_id</span><span>,</span> <span>user_name</span><span>,</span> <span>user_email</span><span>):</span><span>user_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span> <span># Generate a UUID for user_id </span> <span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>sk</span> <span>=</span> <span>f</span><span>"</span><span>user#</span><span>{</span><span>user_id</span><span>}</span><span>"</span><span># Add user item to DynamoDB table </span> <span>table</span><span>.</span><span>put_item</span><span>(</span><span>Item</span><span>=</span><span>{</span><span>'</span><span>PK</span><span>'</span><span>:</span> <span>pk</span><span>,</span><span>'</span><span>SK</span><span>'</span><span>:</span> <span>sk</span><span>,</span><span>'</span><span>user_name</span><span>'</span><span>:</span> <span>user_name</span><span>,</span><span>'</span><span>user_email</span><span>'</span><span>:</span> <span>user_email</span><span>,</span><span>'</span><span>user_id</span><span>'</span><span>:</span> <span>user_id</span> <span># Storing the user_id here for future use </span> <span>}</span><span>)</span><span>print</span><span>(</span><span>f</span><span>"</span><span>User </span><span>{</span><span>user_name</span><span>}</span><span> added for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span><span>return</span> <span>user_id</span> <span># Return user_id so we can use it later for querying </span><span>def</span> <span>add_order</span><span>(</span><span>tenant_id</span><span>,</span> <span>user_id</span><span>,</span> <span>order_amount</span><span>):</span><span>order_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span> <span># Generate a UUID for order_id </span> <span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>sk</span> <span>=</span> <span>f</span><span>"</span><span>order#</span><span>{</span><span>order_id</span><span>}</span><span>"</span><span># Add order item to DynamoDB table </span> <span>table</span><span>.</span><span>put_item</span><span>(</span><span>Item</span><span>=</span><span>{</span><span>'</span><span>PK</span><span>'</span><span>:</span> <span>pk</span><span>,</span><span>'</span><span>SK</span><span>'</span><span>:</span> <span>sk</span><span>,</span><span>'</span><span>user_id</span><span>'</span><span>:</span> <span>user_id</span><span>,</span><span>'</span><span>order_amount</span><span>'</span><span>:</span> <span>Decimal</span><span>(</span><span>order_amount</span><span>)</span><span>}</span><span>)</span><span>print</span><span>(</span><span>f</span><span>"</span><span>Order </span><span>{</span><span>order_id</span><span>}</span><span> added for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span><span>def</span> <span>get_user</span><span>(</span><span>tenant_id</span><span>,</span> <span>user_id</span><span>):</span><span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>sk</span> <span>=</span> <span>f</span><span>"</span><span>user#</span><span>{</span><span>user_id</span><span>}</span><span>"</span><span>response</span> <span>=</span> <span>table</span><span>.</span><span>get_item</span><span>(</span><span>Key</span><span>=</span><span>{</span><span>'</span><span>PK</span><span>'</span><span>:</span> <span>pk</span><span>,</span><span>'</span><span>SK</span><span>'</span><span>:</span> <span>sk</span><span>}</span><span>)</span><span>item</span> <span>=</span> <span>response</span><span>.</span><span>get</span><span>(</span><span>'</span><span>Item</span><span>'</span><span>)</span><span>if</span> <span>item</span><span>:</span><span>print</span><span>(</span><span>f</span><span>"</span><span>User found: </span><span>{</span><span>item</span><span>}</span><span>"</span><span>)</span><span>else</span><span>:</span><span>print</span><span>(</span><span>f</span><span>"</span><span>User </span><span>{</span><span>user_id</span><span>}</span><span> not found for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span><span>def</span> <span>get_orders_for_tenant</span><span>(</span><span>tenant_id</span><span>):</span><span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>response</span> <span>=</span> <span>table</span><span>.</span><span>query</span><span>(</span><span>KeyConditionExpression</span><span>=</span><span>Key</span><span>(</span><span>'</span><span>PK</span><span>'</span><span>).</span><span>eq</span><span>(</span><span>pk</span><span>)</span> <span>&</span> <span>Key</span><span>(</span><span>'</span><span>SK</span><span>'</span><span>).</span><span>begins_with</span><span>(</span><span>"</span><span>order#</span><span>"</span><span>)</span><span>)</span><span>orders</span> <span>=</span> <span>response</span><span>.</span><span>get</span><span>(</span><span>'</span><span>Items</span><span>'</span><span>,</span> <span>[])</span><span>if</span> <span>orders</span><span>:</span><span>print</span><span>(</span><span>f</span><span>"</span><span>Orders for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>: </span><span>{</span><span>orders</span><span>}</span><span>"</span><span>)</span><span>else</span><span>:</span><span>print</span><span>(</span><span>f</span><span>"</span><span>No orders found for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span><span># Example of adding data for multiple tenants </span><span>tenant_1_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span><span>tenant_2_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span><span># Add users and get user IDs </span><span>user_1_id</span> <span>=</span> <span>add_user</span><span>(</span><span>tenant_1_id</span><span>,</span> <span>'</span><span>Alice</span><span>'</span><span>,</span> <span>'</span><span>alice@example.com</span><span>'</span><span>)</span><span>user_2_id</span> <span>=</span> <span>add_user</span><span>(</span><span>tenant_2_id</span><span>,</span> <span>'</span><span>Bob</span><span>'</span><span>,</span> <span>'</span><span>bob@example.com</span><span>'</span><span>)</span><span># Add orders using the generated user_ids </span><span>add_order</span><span>(</span><span>tenant_1_id</span><span>,</span> <span>user_1_id</span><span>,</span> <span>150</span><span>)</span><span>add_order</span><span>(</span><span>tenant_2_id</span><span>,</span> <span>user_2_id</span><span>,</span> <span>200</span><span>)</span><span># Example of querying data </span><span>get_user</span><span>(</span><span>tenant_1_id</span><span>,</span> <span>user_1_id</span><span>)</span><span>get_orders_for_tenant</span><span>(</span><span>tenant_1_id</span><span>)</span><span>import</span> <span>boto3</span> <span>from</span> <span>uuid</span> <span>import</span> <span>uuid4</span> <span>from</span> <span>boto3.dynamodb.conditions</span> <span>import</span> <span>Key</span> <span>from</span> <span>decimal</span> <span>import</span> <span>Decimal</span> <span># Initialize the DynamoDB resource </span><span>dynamodb</span> <span>=</span> <span>boto3</span><span>.</span><span>resource</span><span>(</span><span>'</span><span>dynamodb</span><span>'</span><span>)</span> <span># Function to create the DynamoDB table </span><span>def</span> <span>create_table</span><span>():</span> <span># Create the table if it doesn't exist </span> <span>try</span><span>:</span> <span>table</span> <span>=</span> <span>dynamodb</span><span>.</span><span>create_table</span><span>(</span> <span>TableName</span><span>=</span><span>'</span><span>MultiTenantTable</span><span>'</span><span>,</span> <span>KeySchema</span><span>=</span><span>[</span> <span>{</span> <span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>PK</span><span>'</span><span>,</span> <span>'</span><span>KeyType</span><span>'</span><span>:</span> <span>'</span><span>HASH</span><span>'</span> <span># Partition key </span> <span>},</span> <span>{</span> <span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>SK</span><span>'</span><span>,</span> <span>'</span><span>KeyType</span><span>'</span><span>:</span> <span>'</span><span>RANGE</span><span>'</span> <span># Sort key </span> <span>}</span> <span>],</span> <span>AttributeDefinitions</span><span>=</span><span>[</span> <span>{</span> <span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>PK</span><span>'</span><span>,</span> <span>'</span><span>AttributeType</span><span>'</span><span>:</span> <span>'</span><span>S</span><span>'</span> <span>},</span> <span>{</span> <span>'</span><span>AttributeName</span><span>'</span><span>:</span> <span>'</span><span>SK</span><span>'</span><span>,</span> <span>'</span><span>AttributeType</span><span>'</span><span>:</span> <span>'</span><span>S</span><span>'</span> <span>}</span> <span>],</span> <span>ProvisionedThroughput</span><span>=</span><span>{</span> <span>'</span><span>ReadCapacityUnits</span><span>'</span><span>:</span> <span>5</span><span>,</span> <span>'</span><span>WriteCapacityUnits</span><span>'</span><span>:</span> <span>5</span> <span>}</span> <span>)</span> <span>print</span><span>(</span><span>"</span><span>Creating table... Please wait until it</span><span>'</span><span>s created.</span><span>"</span><span>)</span> <span>table</span><span>.</span><span>meta</span><span>.</span><span>client</span><span>.</span><span>get_waiter</span><span>(</span><span>'</span><span>table_exists</span><span>'</span><span>).</span><span>wait</span><span>(</span><span>TableName</span><span>=</span><span>'</span><span>MultiTenantTable</span><span>'</span><span>)</span> <span>print</span><span>(</span><span>"</span><span>Table </span><span>'</span><span>MultiTenantTable</span><span>'</span><span> created successfully!</span><span>"</span><span>)</span> <span>except</span> <span>Exception</span> <span>as</span> <span>e</span><span>:</span> <span>print</span><span>(</span><span>f</span><span>"</span><span>Error creating table: </span><span>{</span><span>e</span><span>}</span><span>"</span><span>)</span> <span># Initialize table after creation (if it does not exist) </span><span>create_table</span><span>()</span> <span># Now, we can reference the table </span><span>table</span> <span>=</span> <span>dynamodb</span><span>.</span><span>Table</span><span>(</span><span>'</span><span>MultiTenantTable</span><span>'</span><span>)</span> <span>def</span> <span>add_user</span><span>(</span><span>tenant_id</span><span>,</span> <span>user_name</span><span>,</span> <span>user_email</span><span>):</span> <span>user_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span> <span># Generate a UUID for user_id </span> <span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span> <span>sk</span> <span>=</span> <span>f</span><span>"</span><span>user#</span><span>{</span><span>user_id</span><span>}</span><span>"</span> <span># Add user item to DynamoDB table </span> <span>table</span><span>.</span><span>put_item</span><span>(</span> <span>Item</span><span>=</span><span>{</span> <span>'</span><span>PK</span><span>'</span><span>:</span> <span>pk</span><span>,</span> <span>'</span><span>SK</span><span>'</span><span>:</span> <span>sk</span><span>,</span> <span>'</span><span>user_name</span><span>'</span><span>:</span> <span>user_name</span><span>,</span> <span>'</span><span>user_email</span><span>'</span><span>:</span> <span>user_email</span><span>,</span> <span>'</span><span>user_id</span><span>'</span><span>:</span> <span>user_id</span> <span># Storing the user_id here for future use </span> <span>}</span> <span>)</span> <span>print</span><span>(</span><span>f</span><span>"</span><span>User </span><span>{</span><span>user_name</span><span>}</span><span> added for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span> <span>return</span> <span>user_id</span> <span># Return user_id so we can use it later for querying </span> <span>def</span> <span>add_order</span><span>(</span><span>tenant_id</span><span>,</span> <span>user_id</span><span>,</span> <span>order_amount</span><span>):</span> <span>order_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span> <span># Generate a UUID for order_id </span> <span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span> <span>sk</span> <span>=</span> <span>f</span><span>"</span><span>order#</span><span>{</span><span>order_id</span><span>}</span><span>"</span> <span># Add order item to DynamoDB table </span> <span>table</span><span>.</span><span>put_item</span><span>(</span> <span>Item</span><span>=</span><span>{</span> <span>'</span><span>PK</span><span>'</span><span>:</span> <span>pk</span><span>,</span> <span>'</span><span>SK</span><span>'</span><span>:</span> <span>sk</span><span>,</span> <span>'</span><span>user_id</span><span>'</span><span>:</span> <span>user_id</span><span>,</span> <span>'</span><span>order_amount</span><span>'</span><span>:</span> <span>Decimal</span><span>(</span><span>order_amount</span><span>)</span> <span>}</span> <span>)</span> <span>print</span><span>(</span><span>f</span><span>"</span><span>Order </span><span>{</span><span>order_id</span><span>}</span><span> added for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span> <span>def</span> <span>get_user</span><span>(</span><span>tenant_id</span><span>,</span> <span>user_id</span><span>):</span> <span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span> <span>sk</span> <span>=</span> <span>f</span><span>"</span><span>user#</span><span>{</span><span>user_id</span><span>}</span><span>"</span> <span>response</span> <span>=</span> <span>table</span><span>.</span><span>get_item</span><span>(</span> <span>Key</span><span>=</span><span>{</span> <span>'</span><span>PK</span><span>'</span><span>:</span> <span>pk</span><span>,</span> <span>'</span><span>SK</span><span>'</span><span>:</span> <span>sk</span> <span>}</span> <span>)</span> <span>item</span> <span>=</span> <span>response</span><span>.</span><span>get</span><span>(</span><span>'</span><span>Item</span><span>'</span><span>)</span> <span>if</span> <span>item</span><span>:</span> <span>print</span><span>(</span><span>f</span><span>"</span><span>User found: </span><span>{</span><span>item</span><span>}</span><span>"</span><span>)</span> <span>else</span><span>:</span> <span>print</span><span>(</span><span>f</span><span>"</span><span>User </span><span>{</span><span>user_id</span><span>}</span><span> not found for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span> <span>def</span> <span>get_orders_for_tenant</span><span>(</span><span>tenant_id</span><span>):</span> <span>pk</span> <span>=</span> <span>f</span><span>"</span><span>tenant#</span><span>{</span><span>tenant_id</span><span>}</span><span>"</span> <span>response</span> <span>=</span> <span>table</span><span>.</span><span>query</span><span>(</span> <span>KeyConditionExpression</span><span>=</span><span>Key</span><span>(</span><span>'</span><span>PK</span><span>'</span><span>).</span><span>eq</span><span>(</span><span>pk</span><span>)</span> <span>&</span> <span>Key</span><span>(</span><span>'</span><span>SK</span><span>'</span><span>).</span><span>begins_with</span><span>(</span><span>"</span><span>order#</span><span>"</span><span>)</span> <span>)</span> <span>orders</span> <span>=</span> <span>response</span><span>.</span><span>get</span><span>(</span><span>'</span><span>Items</span><span>'</span><span>,</span> <span>[])</span> <span>if</span> <span>orders</span><span>:</span> <span>print</span><span>(</span><span>f</span><span>"</span><span>Orders for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>: </span><span>{</span><span>orders</span><span>}</span><span>"</span><span>)</span> <span>else</span><span>:</span> <span>print</span><span>(</span><span>f</span><span>"</span><span>No orders found for tenant </span><span>{</span><span>tenant_id</span><span>}</span><span>"</span><span>)</span> <span># Example of adding data for multiple tenants </span><span>tenant_1_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span> <span>tenant_2_id</span> <span>=</span> <span>str</span><span>(</span><span>uuid4</span><span>())</span> <span># Add users and get user IDs </span><span>user_1_id</span> <span>=</span> <span>add_user</span><span>(</span><span>tenant_1_id</span><span>,</span> <span>'</span><span>Alice</span><span>'</span><span>,</span> <span>'</span><span>alice@example.com</span><span>'</span><span>)</span> <span>user_2_id</span> <span>=</span> <span>add_user</span><span>(</span><span>tenant_2_id</span><span>,</span> <span>'</span><span>Bob</span><span>'</span><span>,</span> <span>'</span><span>bob@example.com</span><span>'</span><span>)</span> <span># Add orders using the generated user_ids </span><span>add_order</span><span>(</span><span>tenant_1_id</span><span>,</span> <span>user_1_id</span><span>,</span> <span>150</span><span>)</span> <span>add_order</span><span>(</span><span>tenant_2_id</span><span>,</span> <span>user_2_id</span><span>,</span> <span>200</span><span>)</span> <span># Example of querying data </span><span>get_user</span><span>(</span><span>tenant_1_id</span><span>,</span> <span>user_1_id</span><span>)</span> <span>get_orders_for_tenant</span><span>(</span><span>tenant_1_id</span><span>)</span>import boto3 from uuid import uuid4 from boto3.dynamodb.conditions import Key from decimal import Decimal # Initialize the DynamoDB resource dynamodb = boto3.resource('dynamodb') # Function to create the DynamoDB table def create_table(): # Create the table if it doesn't exist try: table = dynamodb.create_table( TableName='MultiTenantTable', KeySchema=[ { 'AttributeName': 'PK', 'KeyType': 'HASH' # Partition key }, { 'AttributeName': 'SK', 'KeyType': 'RANGE' # Sort key } ], AttributeDefinitions=[ { 'AttributeName': 'PK', 'AttributeType': 'S' }, { 'AttributeName': 'SK', 'AttributeType': 'S' } ], ProvisionedThroughput={ 'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5 } ) print("Creating table... Please wait until it's created.") table.meta.client.get_waiter('table_exists').wait(TableName='MultiTenantTable') print("Table 'MultiTenantTable' created successfully!") except Exception as e: print(f"Error creating table: {e}") # Initialize table after creation (if it does not exist) create_table() # Now, we can reference the table table = dynamodb.Table('MultiTenantTable') def add_user(tenant_id, user_name, user_email): user_id = str(uuid4()) # Generate a UUID for user_id pk = f"tenant#{tenant_id}" sk = f"user#{user_id}" # Add user item to DynamoDB table table.put_item( Item={ 'PK': pk, 'SK': sk, 'user_name': user_name, 'user_email': user_email, 'user_id': user_id # Storing the user_id here for future use } ) print(f"User {user_name} added for tenant {tenant_id}") return user_id # Return user_id so we can use it later for querying def add_order(tenant_id, user_id, order_amount): order_id = str(uuid4()) # Generate a UUID for order_id pk = f"tenant#{tenant_id}" sk = f"order#{order_id}" # Add order item to DynamoDB table table.put_item( Item={ 'PK': pk, 'SK': sk, 'user_id': user_id, 'order_amount': Decimal(order_amount) } ) print(f"Order {order_id} added for tenant {tenant_id}") def get_user(tenant_id, user_id): pk = f"tenant#{tenant_id}" sk = f"user#{user_id}" response = table.get_item( Key={ 'PK': pk, 'SK': sk } ) item = response.get('Item') if item: print(f"User found: {item}") else: print(f"User {user_id} not found for tenant {tenant_id}") def get_orders_for_tenant(tenant_id): pk = f"tenant#{tenant_id}" response = table.query( KeyConditionExpression=Key('PK').eq(pk) & Key('SK').begins_with("order#") ) orders = response.get('Items', []) if orders: print(f"Orders for tenant {tenant_id}: {orders}") else: print(f"No orders found for tenant {tenant_id}") # Example of adding data for multiple tenants tenant_1_id = str(uuid4()) tenant_2_id = str(uuid4()) # Add users and get user IDs user_1_id = add_user(tenant_1_id, 'Alice', 'alice@example.com') user_2_id = add_user(tenant_2_id, 'Bob', 'bob@example.com') # Add orders using the generated user_ids add_order(tenant_1_id, user_1_id, 150) add_order(tenant_2_id, user_2_id, 200) # Example of querying data get_user(tenant_1_id, user_1_id) get_orders_for_tenant(tenant_1_id)
Enter fullscreen mode Exit fullscreen mode
Explanation of the Code
-
create_table()
:
This function creates a DynamoDB table namedMultiTenantTable
with a partition key (PK
) and a sort key (SK
). ThePK
contains the tenant identifier, and theSK
differentiates between users, orders, etc. The provisioned throughput is set to 5 read and 5 write capacity units. Adjust this based on your application’s scale. -
add_user()
andadd_order()
:
These functions add users and orders to the table. Data is associated with the tenant usingPK
, and the specific item type (user or order) is differentiated usingSK
. -
get_user()
andget_orders_for_tenant()
:
These functions retrieve data based on the tenant and user identifiers, isolating data per tenant.
Conclusion
By using DynamoDB with a well-designed schema that incorporates multi-tenancy principles, we can efficiently store and query data for multiple tenants in a shared table. This approach ensures data isolation between tenants while leveraging DynamoDB’s scalability and performance.
暂无评论内容