Invalid type error when using Datastax Cassandra Driver - cassandra

I have a case class which represents partition key values.
case class UserKeys (bucket:Int,
email: String)
I create query Clauses as follows:
def conditions(id: UserKeys):List[Clauses] = List(
QueryBuilder.eq("bucket", id.bucket), //TODOM - pick table description from config/env file.
QueryBuilder.eq("email", id.email)
)
And use the query as follows
val selectStmt =
select()
.from(tablename)
.where(QueryBuilder.eq(partitionKeyColumns(0), whereClauseList(0))).and(QueryBuilder.eq(partitionKeyColumns(1), whereClauseList(1)))
.limit(1)
I am getting following error.
com.datastax.driver.core.exceptions.InvalidTypeException: Value 0 of type class com.datastax.driver.core.querybuilder.Clause$SimpleClause does not correspond to any CQL3 type
Question 1 - What am I doing wrong?
The query works on cqlsh
The table I am querying is
CREATE TABLE users (
bucket int,
email text,
firstname text,
lastname text,
authprovider text,
password text,
PRIMARY KEY ((bucket, email), firstname, lastname)
Question 2 - Is there a way to print the List which contains the query clauses? I tried it but I get this incomprehensible text.
List(com.datastax.driver.core.querybuilder.Clause$SimpleClause#2389b3ee, com.datastax.driver.core.querybuilder.Clause$SimpleClause#927f81)

My bad, I was using the query clauses incorrectly. Rather than
.where(QueryBuilder.eq(partitionKeyColumns(0), whereClauseList(0))).and(QueryBuilder.eq(partitionKeyColumns(1), whereClauseList(1)))
I needed to do
.where(whereClauseList(0)).and(whereClauseList(1))
because the List already has QueryBuilder.eq("bucket", id.bucket) part

Related

SyntaxException: line 2:10 no viable alternative at input 'UNIQUE' > (...NOT EXISTS books ( id [UUID] UNIQUE...)

I am trying the following codes to create a keyspace and a table inside of it:
CREATE KEYSPACE IF NOT EXISTS books WITH REPLICATION = { 'class': 'SimpleStrategy',
'replication_factor': 3 };
CREATE TABLE IF NOT EXISTS books (
id UUID PRIMARY KEY,
user_id TEXT UNIQUE NOT NULL,
scale TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT NOT NULL,
reward map<INT,TEXT> NOT NULL,
image_url TEXT NOT NULL,
video_url TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
But I do get:
SyntaxException: line 2:10 no viable alternative at input 'UNIQUE'
(...NOT EXISTS books ( id [UUID] UNIQUE...)
What is the problem and how can I fix it?
I see three syntax issues. They are mainly related to CQL != SQL.
The first, is that NOT NULL is not valid at column definition time. Cassandra doesn't enforce constraints like that at all, so for this case, just get rid of all of them.
Next, Cassandra CQL does not allow default values, so this won't work:
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
Providing the current timestamp for created_at is something that will need to be done at write-time. Fortunately, CQL has a few of built-in functions to make this easier:
INSERT INTO books (id, user_id, created_at)
VALUES (uuid(), 'userOne', toTimestamp(now()));
In this case, I've invoked the uuid() function to generate a Type-4 UUID. I've also invoked now() for the current time. However now() returns a TimeUUID (Type-1 UUID) so I've nested it inside of the toTimestamp function to convert it to a TIMESTAMP.
Finally, UNIQUE is not valid.
user_id TEXT UNIQUE NOT NULL,
It looks like you're trying to make sure that duplicate user_ids are not stored with each id. You can help to ensure uniqueness of the data in each partition by adding user_id to the end of the primary key definition as a clustering key:
CREATE TABLE IF NOT EXISTS books (
id UUID,
user_id TEXT,
...
PRIMARY KEY (id, user_id));
This PK definition will ensure that data for books will be partitioned by id, containing multiple user_id rows.
Not sure what the relationship is between books and users is, though. If one book can have many users, then this will work. If one user can have many books, then you'll want to switch the order of the keys to this:
PRIMARY KEY (user_id, id));
In summary, a working table definition for this problem looks like this:
CREATE TABLE IF NOT EXISTS books (
id UUID,
user_id TEXT,
scale TEXT,
title TEXT,
description TEXT,
reward map<INT,TEXT>,
image_url TEXT,
video_url TEXT,
created_at TIMESTAMP,
PRIMARY KEY (id, user_id));

Cassandra 3.11, Filter Results by list (searching for alternatives)

I want to ask cassandra to filter its results by a list of arguments. But this is not possible on a "normal" column. Or in cassandra's words:
IN predicates on non-primary-key columns (access_right_id) is not yet supported
My table looks like this:
CREATE TABLE "service"
(
course_id uuid,
type text,
access_token uuid,
name_de text,
name_en text,
url text,
edit_right_id uuid,
access_right_id uuid,
PRIMARY KEY (course_id, type, access_token)
);
I want to execute a query like this:
SELECT * FROM service WHERE
course_id = :courseId
AND type = :type
AND access_right_id IN :rights
I am now searching for a solution to my problem. I am thinking of three possible solutions:
Send N times the query (maybe with a materialized view and access_right_id as a primary key part (clustering key))
SELECT * FROM service WHERE
course_id = :courseId
AND type = :type
AND access_right_id = :right
Send a generated query like this:
SELECT * FROM service WHERE
course_id = :courseId
AND type = :type
AND (access_right_id = :right1 OR access_right_id = :right2 OR access_right_id = :right ...)
Send a query without filtering and filter the result in code.
What do you this is best in this case? What is more cassandra "compliant"?
Thank you in advance for your input.

Cassandra insert data into table column with data type set<text>

We're trying to setup an INSERT statement on a table with a set<text> column data type in Cassandra, but have come up with no luck. Here's an example:
INSERT INTO test_table
(my_items)
VALUES
([{"test1":"test val 1","test2":"test val 2"}])
The result is always something like:
no viable alternative at input for [test val ]2
Enclosing values in curly brackets and separate by comma
Example :
Let's we have the schema :
CREATE TABLE users (
user_id text PRIMARY KEY,
first_name text,
last_name text,
emails set<text>
);
Insert :
INSERT INTO users (user_id, first_name, last_name, emails)
VALUES('frodo', 'Frodo', 'Baggins', {'f#baggins.com', 'baggins#gmail.com'});
Update :
UPDATE users SET emails = emails + {'fb#friendsofmordor.org'}
WHERE user_id = 'frodo';
More Using the set type
Edited
If you want to insert value "test1":"test val 1" and "test2":"test val 2" into set then enclose each value with single quote
Example :
INSERT INTO users (user_id, first_name, last_name, emails)
VALUES('2011331035', 'Md Ashraful', 'Islam', {'"test1":"test val 1"', '"test2":"test val 2"'});

Cassandra QueryBuilder not returning any result, whereas same query works fine in CQL shell

SELECT count(*) FROM device_stats
WHERE orgid = 'XYZ'
AND regionid = 'NY'
AND campusid = 'C1'
AND buildingid = 'C1'
AND floorid = '2'
AND year = 2017;
The above CQL query returns correct result - 32032, in CQL Shell
But when I run the same query using QueryBuilder Java API , I see the count as 0
BuiltStatement summaryQuery = QueryBuilder.select()
.countAll()
.from("device_stats")
.where(eq("orgid", "XYZ"))
.and(eq("regionid", "NY"))
.and(eq("campusid", "C1"))
.and(eq("buildingid", "C1"))
.and(eq("floorid", "2"))
.and(eq("year", "2017"));
try {
ResultSetFuture tagSummaryResults = session.executeAsync(tagSummaryQuery);
tagSummaryResults.getUninterruptibly().all().stream().forEach(result -> {
System.out.println(" totalCount > "+result.getLong(0));
});
I have only 20 partitions and 32032 rows per partition.
What could be the reason QueryBuilder not executing the query correctly ?
Schema :
CREATE TABLE device_stats (
orgid text,
regionid text,
campusid text,
buildingid text,
floorid text,
year int,
endofwindow timestamp,
categoryid timeuuid,
devicestats map<text,bigint>,
PRIMARY KEY ((orgid, regionid, campusid, buildingid, floorid,year),endofwindow,categoryid)
) WITH CLUSTERING ORDER BY (endofwindow DESC,categoryid ASC);
// Using the keys function to index the map keys
CREATE INDEX ON device_stats (keys(devicestats));
I am using cassandra 3.10 and com.datastax.cassandra:cassandra-driver-core:3.1.4
Moving my comment to an answer since that seems to solve the original problem:
Changing .and(eq("year", "2017")) to .and(eq("year", 2017)) solves the issue since year is an int and not a text.

Wide column pagination in CQL table

Let say i have this table
CREATE TABLE comments
(
postId uuid,
commentId timeuuid,
postedBy text,
postedById uuid,
text text,
blocked boolean,
anonymous boolean,
PRIMARY KEY(postId, commentId)
)
How can I perform wide column pagination on this table something like :
SELECT * FROM comments WHERE postId = '123' AND commentId > '34566'
I was going through Automatic Paging but confused with three approaches mentioned in this document that which should I use
If you want to compare field for timeuuid, you need to using the expression like below:
SELECT * FROM comments WHERE postId = '123' AND commentId > maxTimeuuid('2013-08-01 15:05-0500')
Once you've received the ResultSet from the execute method, you should be able to simply iterate over it using the iterator method. Pagination will happen automatically, based on the value specified in setFetchSize or the default value of 5000.

Resources