Implementing Multi-Tenancy in DynamoDB with Python

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:

  1. Add Users: Add a user to a specific tenant.
  2. Add Orders: Add an order associated with a user.
  3. Retrieve Users: Retrieve a user by tenant_id and user_id.
  4. 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>boto3
pip <span>install </span>boto3
pip 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

  1. create_table():
    This function creates a DynamoDB table named MultiTenantTable with a partition key (PK) and a sort key (SK). The PK contains the tenant identifier, and the SK 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.

  2. add_user() and add_order():
    These functions add users and orders to the table. Data is associated with the tenant using PK, and the specific item type (user or order) is differentiated using SK.

  3. get_user() and get_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.

原文链接:Implementing Multi-Tenancy in DynamoDB with Python

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
I try to give up the dream just a dream.
努力了才叫梦想
评论 抢沙发

请登录后发表评论

    暂无评论内容