Skip to main content

Work with tenants & data

The team at MyPrivateJournal has now set up a Weaviate instance with a multi-tenant collection. In this section, we will learn how to work with tenants and their data.

Add tenants and data

Once a multi-tenant collection is created, you can manage its tenants through the .tenant namespace.

Each end user in MyPrivateJournal will have their journal entries be backed their own tenant. This means that when a user is onboarded, a tenant is created for them. When a user is offboarded, their tenant is removed.

Create tenants

When a user is onboarded, we can include this code to the onboarding logic.

mt_collection.tenants.create("steve85")  # Create a tenant, e.g. based on a username

Tenant creation can be done in bulk, too.

Let's say that MyPrivateJournal has a batch of new users to onboard, from an organization called AcmeCorp. They could create tenants for multiple users in one operation:

new_usernames = ["bob1", "alice2", "etienne3"]

mt_collection.tenants.create(new_usernames) # Create multiple tenants
Tenant names are case-sensitive

Tenant names are case-sensitive. This means that steve, Steve and STEVE are considered different tenants.

Add data objects

Working with a tenant in a multi-tenant collection is similar to working with a single-tenant collection.

Let's see how MyPrivateJournal can work with data objects in a tenant as

Single object insertion

As an end user (e.g. Steve or steve85) writes a new journal entry, MyPrivateJournal can insert it into Steve's tenant.

from datetime import datetime, timezone

# Start with the collection object and specify the tenant
tenant = mt_collection.with_tenant("steve85")

tenant.data.insert(
properties={
"text": "What amazing food we had at Quay! It was totally worth it.",
"date": datetime(2024, 5, 15).replace(tzinfo=timezone.utc),
"tags": ["restaurant", "experience"],
}
)

Batch data insertion

And if Steve wants to import his journal entries from another system, MyPrivateJournal can insert them in a batch.

Data being inserted

The objects to be added can be a list of dictionaries, as shown here. Note the use of datetime objects with a timezone for DATE type properties.

from datetime import datetime, timezone

journal_entries = [
{
"text": "The Top Gun sequel was amazing!",
"date": datetime(2022, 5, 30).replace(tzinfo=timezone.utc),
"tags": ["movie", "action"],
},
{
"text": "Ahhh the Taylor Swift Eras concert in Denver was sooo much better than I could have hoped for!",
"date": datetime(2023, 7, 14).replace(tzinfo=timezone.utc),
"tags": ["music", "swifties", "concert"],
},
{
"text": "After watching Kate McKinnon play Weird Barbie I totally feel seen.",
"date": datetime(2023, 7, 25).replace(tzinfo=timezone.utc),
"tags": ["movie", "barbie", "happy"],
},
{
"text": "Spring is here and I'm loving the new flowers in the garden!",
"date": datetime(2024, 4, 5).replace(tzinfo=timezone.utc),
"tags": ["garden", "home"],
},
{
"text": "I went to a cooking class and learned how to make sushi!",
"date": datetime(2024, 5, 16).replace(tzinfo=timezone.utc),
"tags": ["cooking", "hobby"],
},
{
"text": "The new taco place in town is amazing!",
"date": datetime(2024, 7, 20).replace(tzinfo=timezone.utc),
"tags": ["food", "restaurant"],
},
]
tenant = mt_collection.with_tenant("steve85")

with tenant.batch.fixed_size(100) as batch:
for journal_entry in journal_entries:
batch.add_object(journal_entry)

Bonus: Auto tenant creation

If MyPrivateJournal has enabled auto-tenant creation, they can insert data without explicitly creating a tenant. In this example, the specified tenant does not exist, but Weaviate will create it automatically.

This allows MyPrivateJournal to delay creating a tenant until the user writes their first journal entry.

nonexistent_tenant = mt_collection.with_tenant("newsteve15")

nonexistent_tenant.data.insert({
"date": datetime(2024, 7, 7).replace(tzinfo=timezone.utc),
"tags": ["events", "grand prix"],
"text": "Going to Silverstone was a dream come true!",
})

Query tenant data

Once Steve's tenant has been created and populated with data, MyPrivateJournal can allow Steve to interact with his data.

For an application like this, MyPrivateJournal might allow Steve to:

  • Retrieve his journal entries for a date range, and
  • Search for entries

The good news is that just like our data operations, retrieving and querying data in a tenant is very similar to working with a single-tenant collection.

Retrieve entries for a date range

To retrieve Steve's journal entries for a specific date range, MyPrivateJournal can use a query like this:

from weaviate.classes.query import Filter
from datetime import datetime, timezone

tenant = mt_collection.with_tenant("steve85")

start_date = datetime(2023, 7, 1).replace(tzinfo=timezone.utc)
end_date = datetime(2023, 7, 31).replace(tzinfo=timezone.utc)

response = tenant.query.fetch_objects(
filters=(
Filter.by_property("date").greater_or_equal(start_date) &
Filter.by_property("date").less_or_equal(end_date)
),
limit=10
)
Example response

Such a query should return a response like:

{
"text": "Ahhh the Taylor Swift Eras concert in Denver was sooo much better than I could have hoped for!",
"date": datetime.datetime(2023, 7, 14, 0, 0, tzinfo=datetime.timezone.utc),
"tags": ["music", "swifties", "concert"],
}
{
"text": "After watching Kate McKinnon play Weird Barbie I totally feel seen.",
"date": datetime.datetime(2023, 7, 25, 0, 0, tzinfo=datetime.timezone.utc),
"tags": ["movie", "barbie", "happy"],
}

Search for entries

Additionally, Steve might want to search for entries. For example - he might want to search for entries relating to some food experience that he had.

MyPrivateJournal can leverage Weaviate's hybrid search to help Steve find the most relevant entries.

tenant = mt_collection.with_tenant("steve85")

response = tenant.query.hybrid(
query="food experience",
limit=2
)
Example response
{
"date": datetime.datetime(2024, 5, 15, 0, 0, tzinfo=datetime.timezone.utc),
"tags": ["restaurant", "experience"],
"text": "What amazing food we had at Quay! It was totally worth it.",
}
{
"date": datetime.datetime(2024, 5, 16, 0, 0, tzinfo=datetime.timezone.utc),
"tags": ["cooking", "hobby"],
"text": "I went to a cooking class and learned how to make sushi!",
}

You can see that the search syntax is essentially identical to that of a single-tenant collection. So, any search method available for a single-tenant collection can be applied to a multi-tenant collection.

Summary

In this section, we learned how to work with tenants and their data in a multi-tenant collection. We saw how to create tenants, add data objects, and query tenant data.

In the next section, we will learn how MyPrivateJournal can keep their application running smoothly and efficiently by managing tenants.

Questions and feedback

If you have any questions or feedback, let us know in the user forum.