How to update and replace in Cassandra a UDT field value? - cassandra

Does Cassandra support update of a UDT field value? something like replacing it with a new value?
I have user_fav_payment_method UDT and I need to replace cash with debit card:
update user_ratings set
user_fav_payment_method{'cash'} = {'debit cards'}
where rating_id = 66;
This code is wrong but I need to do something similar to this, how can i do it?

Per documentation:
In Cassandra 3.6 and later, user-defined types that include only non-collection fields can update individual field values. Update an individual field in user-defined type data using the UPDATE command. The desired key-value pair are defined in the command. In order to update, the UDT must be defined in the CREATE TABLE command as an unfrozen data type.
You can use . notation to update only individual fields of the non-frozen UDT, like this:
cqlsh> use test;
cqlsh:test> create type payment_method ( method text, data text);
cqlsh:test> create table users (id int primary key, pay_method payment_method);
cqlsh:test> insert into users (id, pay_method) values (1, {method: 'cash', data: 'usd'});
cqlsh:test> select * from users;
id | pay_method
----+-------------------------------
1 | {method: 'cash', data: 'usd'}
(1 rows)
cqlsh:test> update users set pay_method.method = 'card' where id = 1;
cqlsh:test> select * from users;
id | pay_method
----+-------------------------------
1 | {method: 'card', data: 'usd'}
(1 rows)

Related

Get value from specific map-key in Cassandra

For example. I have a map under the column 'users' in a table called 'table' with primary key 'Id'.
If the map looks like this, {{'Phone': '1234567899'}, {'City': 'Dublin'}}, I want to get the value from key 'Phone' for specific 'Id', in Cassandra database.
Yes, that's possible to do with CQL when using a MAP collection.
To test this, I created a simple table using the specifications and data you mentioned above:
> CREATE TABLE stackoverflow.usermap (
id text PRIMARY KEY,
users map<text, text>);
> INSERT INTO usermap (id,users)
VALUES ('1a',{'Phone': '1234567899','City': 'Dublin'});
> SELECT * FROM usermap WHERE id='1a';
id | users
----+-------------------------------------------
1a | {'City': 'Dublin', 'Phone': '1234567899'}
(1 rows)
Then, I queried with the same WHERE clause, but altering my SELECT to pull back the user's phone only:
> SELECT users['Phone'] FROM usermap WHERE id='1a';
users['Phone']
----------------
1234567899
(1 rows)

Cassandra migrate int to bigint

What would be the easiest way to migrate an int to a bigint in Cassandra? I thought of creating a new column of type bigint and then running a script to basically set the value of that column = the value of the int column for all rows, and then dropping the original column and renaming the new column. However, I'd like to know if someone has a better alternative, because this approach just doesn't sit quite right with me.
You could ALTER your table and change your int column to a varint type. Check the documentation about ALTER TABLE, and the data types compatibility matrix.
The only other alternative is what you said: add a new column and populate it row by row. Dropping the first column can be entirely optional: if you don't assign values when performing insert everything will stay as it is, and new records won't consume space.
You can ALTER your table to store bigint in cassandra with varint. See the example-
cassandra#cqlsh:demo> CREATE TABLE int_test (id int, name text, primary key(id));
cassandra#cqlsh:demo> SELECT * FROM int_test;
id | name
----+------
(0 rows)
cassandra#cqlsh:demo> INSERT INTO int_test (id, name) VALUES ( 215478936541111, 'abc');
cassandra#cqlsh:demo> SELECT * FROM int_test ;
id | name
---------------------+---------
215478936541111 | abc
(1 rows)
cassandra#cqlsh:demo> ALTER TABLE demo.int_test ALTER id TYPE varint;
cassandra#cqlsh:demo> INSERT INTO int_test (id, name) VALUES ( 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999, 'abcd');
cassandra#cqlsh:demo> SELECT * FROM int_test ;
id | name
------------------------------------------------------------------------------------------------------------------------------+---------
215478936541111 | abc
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 | abcd
(2 rows)
cassandra#cqlsh:demo>

Timestamp with auto increment in Cassandra

Want to write System.currentMiliseconds in the cassandta table for each column by cassandra. For example
writeToCassandra(name, email)
in cassandra table:
--------------------------------
name | email| currentMiliseconds
Can cassandra prepare currentMiliseconds column automatically like auto increment ?
BR!
Cassandra has some sort of columnar database taste inside. So if you read docs how the columns are stored inside SSTable, you'll notice that each column has a personal write timestamp appended (used for conflict resolution, like last-write-wins strategy). You can query for that timestamp using writetime() function:
cqlsh:so> create table ticks ( id text primary key, value int);
cqlsh:so> insert into ticks (id, value) values ('foo', 1);
cqlsh:so> insert into ticks (id, value) values ('bar', 2);
cqlsh:so> insert into ticks (id, value) values ('baz', 3);
cqlsh:so> select id, value from ticks;
id | value
-----+-------
bar | 2
foo | 1
baz | 3
(3 rows)
cqlsh:so> select id, writetime(value) from ticks;
id | writetime(value)
-----+------------------
bar | 1448282940862913
foo | 1448282937031542
baz | 1448282945591607
(3 rows)
As you requested, I've not explicitly inserted write timestamp to DB, but able to query it. Note you cannot use writetime() function for PK.
You can try with: dateof(now())
e.g.
INSERT INTO YOUR_TABLE (NAME, EMAIL, DATE)
VALUES ('NAME', 'EMAIL', dateof(now()));

Not getting exact output using User defined data types in cassandra

In CASSANDRA, I created a User defined data type,
cqlsh:test> create type fullname ( firstname text, lastname text );
And i created a table with that data type and inserted into the table like this,
cqlsh:test> create table people ( id UUID primary key, names set < frozen <fullname>> );
cqlsh:test> insert into people (id, names) values (
... now(),
... {{firstname: 'Jim', lastname: 'Jones'}}
... );
When i querying into the table iam getting output with some additional values like this
cqlsh:test> SELECT * from people ;
id | names
--------------------------------------+--------------------------------------------
3a59e2e0-14df-11e5-8999-abcdb7df22fc | {\x00\x00\x00\x03Jim\x00\x00\x00\x05Jones}
How can i get output like this???
select * from people;
id | names
--------------------------------------+-----------------------------------------
69ba9d60-a06b-11e4-9923-0fa29ba414fb | {{firstname: 'Jim', lastname: 'Jones'}}

How Can I Search for Records That Have A Null/Empty Field Using CQL?

How can I write a query to find all records in a table that have a null/empty field? I tried tried the query below, but it doesn't return anything.
SELECT * FROM book WHERE author = 'null';
null fields don't exist in Cassandra unless you add them yourself.
You might be thinking of the CQL data model, which hides certain implementation details in order to have a more understandable data model. Cassandra is sparse, which means that only data that is used is actually stored. You can visualize this by adding in some test data to Cassandra through CQL.
cqlsh> CREATE KEYSPACE test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1 } ;
cqlsh> use test ;
cqlsh:test> CREATE TABLE foo (name text, age int, pet text, primary key (name)) ;
cqlsh:test> insert into foo (name, age, pet) values ('yves', 81, 'german shepherd') ;
cqlsh:test> insert into foo (name, pet) values ('coco', 'ferret') ;
cqlsh:test> SELECT * FROM foo ;
name | age | pet
-----+-----+------------------
coco | null | ferret
yves | 81 | german shepherd
So even it appears that there is a null value, the actual value is nonexistent -- CQL is showing you a null because this makes more sense, intuitively.
If you take a look at the table from the Thrift side, you can see that the table contains no such value for coco's age.
$ bin/cassandra-cli
[default#unknown] use test;
[default#test] list foo;
RowKey: coco
=> (name=, value=, timestamp=1389137986090000)
=> (name=age, value=00000083, timestamp=1389137986090000)
-------------------
RowKey: yves
=> (name=, value=, timestamp=1389137973402000)
=> (name=age, value=00000051, timestamp=1389137973402000)
=> (name=pet, value=6765726d616e207368657068657264, timestamp=1389137973402000)
Here, you can clearly see that yves has two columns: age and pet, while coco only has one: age.
As far as I know you cannot do this with NULL.
As an alternative, you could use a different empty value, for example the empty string: ''
In that case you could select all books with an empty author like this (assuming the author column is appropriately indexed):
SELECT * FROM book WHERE author = '';
If your_column_name in your_table is a text data type then following should work,
SELECT * FROM your_table WHERE your_column_name >= '' ALLOW FILTERING;
You can try language hacks depending on your usecase;
eg:
if you have a column: column_a, which holds only positive integer values.
for this usecase to filter results by Null values of this column,
you can apply the condition as:
where column_a <0
This will work if you are using Solr over Cassandra but not sure about direct Cassandra query.
SELECT * FROM BOOK WHERE solr_query = ' -author : [* TO *] '

Resources