Cassandra Select Query using Collection Primary Key in Where Clause - collections

I'm new to Cassandra and I created a table with a frozen collection as the primary key
cqlsh> create table rick_morty (id uuid, name text, adventure text, instigator frozen<set<text>>, PRIMARY KEY((instigator), adventure, name, id));
Now I want to query based on the primary key (instigator) for all of the values held in the collection. I have found that if I just wanted to query on 1 value, I can use CONTAINS 'contained_value', but I want to query on the entire collection.
I've been looking all over to figure out how to do this but I can't find the answer.
Doing something like
const query = 'SELECT name from rick_morty';
retrieves all results but I want to do something like...
const query = 'SELECT name from rick_morty where instigator = ["Rick", "Morty", "Beth"]';
to retrieve all list of names associated with that array of instigators.
Is this possible?? Did I just create my table in an improper way?

Is this possible??
Yes. See #8 here.
"Filter data on a column of a user-defined type. Create an index and then run a conditional query. In Cassandra 2.1.x, you need to list all components of the name column in the WHERE clause."
This should work:
SELECT name from rick_morty where instigator = { 'Rick', 'Morty', 'Beth'};

The following query should work,
SELECT name from rick_morty where instigator contains 'Rick' AND contains 'Morty';
But, This may not be an efficient/proper way to implement as Sets are meant to be used to store/get a set of data for a given primary key.
So, I would recommend you to re-design the data model by denormolise the query into a an additional table in case if this requirement is one of your primary use case.

Related

How to future proof these possible requirement changes (swaping primary key columns) with a dynamodb table design?

I have the following data structure
item_id String
version String
_id String
data String
_id is simply a UUID to identify the item. There is no need to search for a row by this field yet.
As of now, item_id, an id generated by an external system, is the a primary key. i.e. Given the item_id, I want to be able retrieve version, _id and data from the dynamodb table.
item_id -> (version, _id, data)
Therefore I am setting item_id as the partition key.
I have two questions for future-proofing (evolution of) the above "schema":
In the future, if I want to incorporate version (version number of the item) into the primary key, can I just modify the table and add it to be the partition key?
If I also want to make the data searchable by _id, is it feasible modify the table to assign _id to be the partition key (It is a unique value because it is a UUID) and reassign item_id to be a search key?
I want to avoid creation of new dynamodb table and data migration to create new key structures, because it may lead to down time.
You cannot update primary keys in DynamoDB. From the docs:
You cannot use UpdateItem to update any primary key attributes. Instead, you will need to delete the item, and then use PutItem to create a new item with new attributes.
If you wanted to make data searchable by _id, you could introduce a secondary index with the _id field as the partition key of the index.
For example, let's say your data looked like this:
If you defined a secondary index on _id, the index would look like this (same data as the previous example, just a different logical view):
DynamoDB doesn't currently have any native versioning functionality, so you'll have to incorporate that into your data model. Fortunately, there's lots of discussion about this use case on the web. AWS has a document of DynamoDB "Best Practices", including an example of versioning.

How to fetch multiple rows from DynamoDB using a non primary key

select * from tableName where columnName="value";
How can I fetch a similar result in DynamoDB using java, without using primary key as my attribute (Need to group data based on a value for a particular column).
I have gone through articles regarding getbatchitems, QuerySpec but all these require me to pass the primary key.
Can someone give a lead here?
Short answer is you can't. Whenever you use the Query or GetItem operations in DynamoDB you must always supply the table or index primary key.
You have two options:
Perform a Scan operation on the table and filter by columnName="value". However this requires DynamoDB to look at every item in the table so it is likely to be slow and expensive.
Add a Global Secondary Index to your table. This will require you to define a primary key for the index that contains the columnName you want to query

How to update a aprimary key field with linq to SQL?

I have tbl_names with following fields:
Id int
Name nvarchar(10)
family nvarchar(20)
Id Name Family
1 John Smith
and suppose Id and name are primary key together(compound primary key).
and I want to update name field according to the value of Id field.
DataclassesContext dac=new DataClassesContext();
var query=from record in Dac.tbl_name where record.id=1 select record;
query.name="Raymond";
Dac.Submitchanges();
but I encounter following error:
Value of member 'co_Workshop' of an object of type 'Tbl_Workshop' changed.
A member defining the identity of the object cannot be changed.
Consider adding a new object with new identity and deleting the existing one instead.
Is it because of name field is primary key? why can't I update a primary key field using linq?
I am not sure that you should find a way around this. I cannot imagine why it would be a good idea to change a value in a PK. The entire nature of a PK is that it is a stable identifier of the row.
In your case, you should drop and recreate the PK to be just the "Id" field and then if you need to improve performance on queries filtering on "name" then just add an Index on the "name" field. The fact that you only use the "Id" field to find the record supports this idea.
EDIT:
I answered before there were comments to the Question. Now that I see the comment from the OP about "it is an old database and can't change it's structure", I would say that if there are no FKs pointing to this PK then this should be a fairly straight-forward change (to drop and recreate the PK with just the "Id" field as I mentioned above). If there are FKs pointing to it then an option (though not a great option and it might not work on all RDBMS's) is to:
Drop the FKs
Drop the PK
Create the new PK on just the "Id" field
Create a UNIQUE INDEX on "Id" and "Name"
Recreate the FK's to point to the UNIQUE INDEX
This will work on Microsoft SQL Server and as much as I dislike the idea of a FK pointing to a UNIQUE INDEX, it should allow for the same structure that you have now plus LINQ will just see the single field PK on "Id" and allow for the update.
Where possible, a workaround is to delete the record whose primary key value needs updating and create a new record in its place.
It looks like there are ways around it, like I mentioned above. Linq won't let you change the primary key.
http://social.msdn.microsoft.com/Forums/en/linqprojectgeneral/thread/64064c2d-1484-4a00-a2c4-764bcb6b774a
Had the same problem. For legacy reasons, I couldn't remove the column I needed to update from being part of the primary key.
A simple solution was to not use Linq in this case, but use T_SQL and do a simple update.
update tbl_name set name = 'Raymond' where id = 1

SQLite Query to Insert a record If not exists

I want to insert a record into a sqlite table if its actually not inserted.
Let's say it has three fields pk, name, address
I want to INSERT new record with name if that name not added preveously.
Can we do with this in a single Query. Seems like its slightly different from SQL Queries sometimes.
Yes, you can do that with a single query.
INSERT ON CONFLICT IGNORE should help you: http://www.sqlite.org/lang_conflict.html
Put a unique key on the name, this will create a conflict when you try inserting a record if the name already exists.
The default is ABORT, so without the IGNORE, the statement will return an error. If you don't want that, use IGNORE.
If you can't make use of a UNIQUE INDEX in combination with INSERT INTO or INSERT OR IGNORE INTO, you could write a query like this;
INSERT INTO table (column)
SELECT value
WHERE NOT EXISTS (SELECT 1
FROM table
WHERE column = value)

SQLITE: Unable to remove an unnamed primary key

I have a sqlite table that was originally created with:
PRIMARY KEY (`column`);
I now need to remove that primary key and create a new one. Creating a new one is easy, but removing the original seems to be the hard part. If I do
.indices tablename
I don't get the primary key. Some programs show the primary key as
Indexes: 1
[] PRIMARY
The index name is typically in the [].
Any ideas?
You can't.
PRAGMA INDEX_LIST('MyTable');
will give you a list of indices. This will include the automatically generated index for the primary key which will be called something like 'sqlite_autoindex_MyTable_1'.
But unfortunately you cannot drop this index...
sqlite> drop index sqlite_autoindex_MyTable_1;
SQL error: index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped
All you can do is re-create the table without the primary key.
I the database glossary; a primary-key is a type of index where the index order is typically results in the physical ordering of the raw database records. That said any database engine that allows the primary key to be changed is likely reordering the database... so most do not and the operation is up to the programmer to create a script to rename the table and create a new one. So if you want to change the PK there is no magic SQL.
select * from sqlite_master;
table|x|x|2|CREATE TABLE x (a text, b text, primary key (`a`))
index|sqlite_autoindex_x_1|x|3|
You'll see that the second row returned from my quick hack has the index name in the second column, and the table name in the third. Try seeing if that name is anything useful.

Resources