Search code examples
cassandracql

Cassandra delete/update a row and get its previous value


How can I delete a row from Cassandra and get the value it had just before the deletion?

I could execute a SELECT and DELETE query in series, but how can I be sure that the data was not altered concurrently between the execution of those two queries?

I've tried to execute the SELECT and DELETE queries in a batch but that seems to be not allowed.

cqlsh:foo> BEGIN BATCH
       ...     SELECT * FROM data_by_user WHERE user = 'foo';
       ...     DELETE FROM data_by_user WHERE user = 'foo';
       ... APPLY BATCH;
SyntaxException: line 2:4 mismatched input 'SELECT' expecting K_APPLY (BEGIN BATCH    [SELECT]...)

In my use case I have one main table that stores data for items. And I've build several tables that allow to lookup items based on those informations. If I delete an item from the main table, I must also remove it from the other tables.

CREATE TABLE items (id text PRIMARY KEY, owner text, liking_users set<text>, ...);

CREATE TABLE owned_items_by_user (user text, item_id text, PRIMARY KEY ((user), item_id));
CREATE TABLE liked_items_by_user (user text, item_id tect, PRIMARY KEY ((user), item_id));
...

I'm afraid the tables might contain wrong data if I delete an item and at the same time someone e.g. hits the like button of that same item.

  • The deleteItem method execute a SELECT query to fetch the current row of the item from the main table
  • The likeItem method that gets executed at the same times runs an UPDATE query and inserts the item into the owned_items_by_user, liked_items_by_user, ... tables. This happens after the SELECT statement was executed and the UPDATE query is executed before the DELETE query.
  • The deleteItem method deletes the items from the owned_items_by_user, liked_items_by_user, ... tables based on the data just retrieved via the SELECT statement. This data does not yet contain the just added like. The item is therefore deleted, but the just added like remains in the liked_items_by_user table.

Solution

  • You can do a select beforehand, then do a lightweight transaction on the delete to ensure that the data still looks exactly like it did when you selected. If it does, you know the latest state before you deleted. If it does not, keep retrying the whole procedure until it sticks.