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. 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.