Cassandra Top
Explore Cassandra in the DataStax Cloud – Astra – using the monthly free credits.
Persistence top

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we'll be talking about the frozen keyword in the Apache Cassandra database. First, we'll show how to declare the frozen collections or user-defined types (UDTs). Next, we'll discuss examples of usage and how it affects the basic operations of persistent storage.

Further reading:

Build a Dashboard Using Cassandra, Astra, and Stargate

Learn how to build a dashboard using DataStax Astra, a database-as-a-service powered by Apache Cassandra and Stargate APIs.

Build a Dashboard With Cassandra, Astra and CQL – Mapping Event Data

Learn how to display events on an interactive map, based on data stored in an Astra database.

2. Cassandra Database Configuration

Let's create a database using a docker image and connect it to the database using cqlsh. Next, we should create a keyspace:

CREATE KEYSPACE mykeyspace WITH replication = {'class':'SimpleStrategy', 'replication_factor' : 1};

For this tutorial, we created a keyspace with only one copy of the data. Now, let's connect the client session to a keyspace:

USE mykeyspace;

3. Freezing Collection Types

A column whose type is a frozen collection (set, map, or list) can only have its value replaced as a whole. In other words, we can't add, update, or delete individual elements from the collection as we can in non-frozen collection types. So, the frozen keyword can be useful, for example, when we want to protect collections against single-value updates.

Moreover, thanks to freezing, we can use a frozen collection as the primary key in a table. We can declare collection columns by using collection types like set, list, or map. Then we add the type of collection.

To declare a frozen collection, we have to add the keyword before the collection definition:

CREATE TABLE mykeyspace.users
(
    id         uuid PRIMARY KEY,
    ip_numbers frozen<set<inet>>,
    addresses  frozen<map<text, tuple<text>>>,
    emails     frozen<list<varchar>>,
);

Let's insert some data:

INSERT INTO mykeyspace.users (id, ip_numbers)
VALUES (6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47, {'10.10.11.1', '10.10.10.1', '10.10.12.1'});

Importantly, as we mentioned above, a frozen collection can be replaced only as a whole. This means that we can't add or remove elements. Let's try to add a new element to the ip_numbers set:

UPDATE mykeyspace.users
SET ip_numbers = ip_numbers + {'10.10.14.1'}
WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47;

After executing the update, we'll get the error:

InvalidRequest: Error from server: code=2200 [Invalid query] message="Invalid operation (ip_numbers = ip_numbers + {'10.10.14.1'}) for frozen collection column ip_numbers"

If we want to update the data in our collection, we need to update the whole collection:

UPDATE mykeyspace.users
SET ip_numbers = {'11.10.11.1', '11.10.10.1', '11.10.12.1'}
WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b47;

3.1. Nested Collections

Sometimes we have to use nested collections in the Cassandra database. Nested collections are possible only if we mark them as frozen. This means that this collection will be immutable. We can freeze nested collections in both frozen and non-frozen collections. Let's see an example:

CREATE TABLE mykeyspace.users_score
(
    id    uuid PRIMARY KEY,
    score set<frozen<set<int>>>
);

4. Freezing User-Defined Type

User-defined types (UDTs) can attach multiple data fields, each named and typed, to a single column. The fields that are used to create user-defined types may be any valid data type, including collection or other UDTs. Let's create our UDT:

CREATE TYPE mykeyspace.address (
    city text,
    street text,
    streetNo int,
    zipcode text
);

Let's see the declaration of a frozen user-defined type:

CREATE TABLE mykeyspace.building
(
    id      uuid PRIMARY KEY,
    address frozen<address>
);

When we use frozen on a user-defined type, Cassandra treats the value like a blob. This blob is obtained by serializing our UDT to a single value. So, we can't update parts of a user-defined type value. We have to overwrite the entire value.

Firstly, let's insert some data:

INSERT INTO mykeyspace.building (id, address)
VALUES (6ab09bec-e68e-48d9-a5f8-97e6fb4c9b48,
  {city: 'City', street: 'Street', streetNo: 2,zipcode: '02-212'});

Let's see what happen when we try to update only one field:

UPDATE mykeyspace.building
SET address.city = 'City2'
WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b48;

We'll get the error again:

InvalidRequest: Error from server: code=2200 [Invalid query] message="Invalid operation (address.city = 'City2') for frozen UDT column address"

So, let's update the entire value:

UPDATE mykeyspace.building
SET address = {city : 'City2', street : 'Street2'}
WHERE id = 6ab09bec-e68e-48d9-a5f8-97e6fb4c9b48;

This time, the address will be updated. Fields not included in the query are completed with the null value.

5. Tuples

Unlike other composing types, a tuple is always frozen. Therefore, we don't have to mark tuples with the frozen keyword. Consequently, it is not possible to update only some elements of a tuple. As is the case with frozen collections or UDTs, we have to overwrite the entire value.

6. Conclusion

In this quick tutorial, we explored the basic concept of freezing components in the Cassandra database. Next, we created frozen collections and user-defined types. Then, we checked the behavior of these data structures. After that, we talked about the tuples data type. As always, the complete source code of the article is available over on GitHub.

Persistence bottom
Get started with Spring Data JPA through the reference Learn Spring Data JPA course: >> CHECK OUT THE COURSE
Persistence footer banner
guest
0 Comments
Inline Feedbacks
View all comments