Can we add primary key to collection datatypes? - cassandra

When I tried to retrieve table using contains keyword it prompts "Cannot use CONTAINS relation on non collection column col1" but when I tried to create table using
CREATE TABLE test (id int,address map<text, int>,mail list<text>,phone set<int>,primary key (id,address,mail,phone));
it prompts "Invalid collection type for PRIMARY KEY component phone"

One of the basics in Cassandra is that you can't modify primary keys. Always keep that in mind.
You can't use a collection as primary key unless it is frozen, meaning you can't modify it.
This will work
CREATE TABLE test (id int,address frozen<map<text, int>>,mail frozen<list<text>>,phone frozen<set<int>>,primary key (id,address,mail,phone));;
However, I think you should take a look at this document: http://www.datastax.com/dev/blog/cql-in-2-1
You can put secondary indexes on collections after cql 2.1. You may want to use that functionality.

Related

Can OrmLite specify foreign key to an attribute other than the primary key

I have a table structure where a foreign key from Employee table references something other than the primary key of the Department table. This is for historical reasons, so that's just the way it is.
This works: q.Join<Department>((e, d) => e.DepartmentId == d.DepNo);. Note that Department's primary key is Id.
Now, is there any way I could specify the join relationship (with the column name)? The reason is that I'd like to use AutoQuery's built-in IJoin<Employee,Department> thing, but that doesn't let me specify the columns to use.
Please see docs on Reference Conventions for how to define implicit PK and FK references.
AutoQuery only supports implicit references, if you need more customized behavior you’ll need to create a custom AutoQuery implementation.

Set Kentico primary key value when inserting TreeNode

With Kentico 13, I'm looking for a way to specify the primary key value when inserting a TreeNode via API. Something like:
var node = TreeNode.New("MyPageType");
node.SetValue("MyPageTypeID", 1234);
node.Insert(parentNode);
This needs to set the primary key in the MyPageType table so needs SQL identity insert on, and also needs to set the DocumentForeignKeyValue in the CMS_Document table.
The only way I have thought of doing it is with some custom SQL after the node is created, but feels like a hack. Is there a better way?
This is for a content migration task of thousands of documents. After the content migration the default SQL & primary key behavior will be used.
In case anyone finds this, the solution I came up with was to run the content migration script with the old primary key value in a temporary column. After migration I ran SQL to update Kentico references to the old primary key, remove the old primary key, and change the primary key to the temporary column. A bit nasty, but got the job done.

Name the primary key of Container in Cosmbos DB Sql Api different than "id"

I am working on Azure and I have created a database with Cosmos DB SQL API. After creating a container I see that the primary key is always named "id". Is there any way to create a container with PK with name different than "id"?
Every document has a unique id called id. This cannot be altered. If you don't set a value, it is assigned a GUID.
When using methods such as ReadDocument() (or equivalent, based on the SDK) for direct reads instead of queries, a document's id property must be specified.
Now, as far as partitioning goes, you can choose any property you want to use as the partition key.
And if you have additional domain-specific identifiers (maybe a part number), you can always store those in their own properties as well. In this example though, just remember that, while you can query for documents containing a specific part number, you can only do a direct-read via id. If direct reads will be the majority of your read operations, then it's worth considering the use of id to store such a value.
PK = primary key, by the way ;) It's the "main" key for the record, it is not private :)
And no, as far as I know you cannot change the primary key name. It is always "id". Specifically it must be in lowercase, "Id" is not accepted.

Data modelling for consistent secondary keys with Cassandra

With Cassandra,
I want to represent all users objects with a unique uuid, but also contain a set of zero or more secondary user keys to map to a user. Each secondary key should map to one and only one user(id). Because I need to be able to quick lookup of secondarykey to find a user, I maintain a separate lookup table, instead of a secondary INDEX.
I've modelled the data like this, but I am open to alternatives:
CREATE TABLE users (
userid uuid PRIMARY KEY,
name text,
secondarykeys set<text>
);
CREATE TABLE user_secondarykeys (
secondarykey text,
userid uuid,
PRIMARY KEY(secondarykey)
);
A typical use case is this:
I got this user with a secondary key mail:andreas#example.org, and I would like to see if there exists any user with that secondary key, and if it do not exists, I would like to create a new user object.
I can look for the secondary key:
SELECT * FROM "user_secondarykeys" WHERE secondarykey = "mail:andreas#example.org";
and if I do not find any matches, I can insert a new user:
BEGIN BATCH
INSERT INTO users (userid, name, secondarykeys) VALUES (77059e45-5fac-460b-9c4f-47528c292be0, "Andreas", {'mail:andreas#example.org'});
INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas#example.org', 77059e45-5fac-460b-9c4f-47528c292be0);
APPLY BATCH;
My problem is that this can lead to inconsistent data, because a user can be inserted with that secondary key in the meantime between my select and my inserts.
I'm thinking that if I can make my INSERT transaction fail if the secondary key already exists in user_secondarykeys, that would work, because it should then also revert the insert into the users table, because of the atomic property of the transaction. However, I do not know any ways to make the INSERT fail if the secondary key exists. If I add IF NOT EXISTS to the second insert, it will not revert the trasaction it will just avoid inserting into user_secondarykeys, but it will still insert into users.
Any suggestions on how to implement this use case in a reliable way is appreciated. Thanks.
At first, I think that your model is pretty complicated, and I'm not sure if I understand correctly all of your requirements.
So if you get at first this secondary key, and then you have to decide what to do - add user or not - then the following will work for you:
Instead of checking user_secondarykeys table with SELECT statement for occurrence of particular secondary key, go with the following:
INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas#example.org', 77059e45-5fac-460b-9c4f-47528c292be0) IF NOT EXISTS;
So if it applies, it means that this secondary key is not connected with any user - so there are two cases: user doesn't exists or user exists and someone want's to add new secondary key for him. The following will do the job in both cases:
INSERT INTO users(userid, name, secondarykeys) VALUES(77059e45-5fac-460b-9c4f-47528c292be0, 'Andreas', secondarykeys = secondarykeys + 'mail:andreas#example.org')
Because inserts/updates in Cassandra are idempotent(except counters), this will work even if there will be already an user with that id in users table - this should just add another secondary key for him.
Pros of this solution are that you will remove this gap in time which can make you 'inconsistent'. You have a guarantee that no one will insert two users with the same secondary key. You specified that user can have no secondary keys at all - in this situation you can add him straight to the users table.
I'm thinking that if I can make my INSERT transaction fail if the secondary key already exists in user_secondarykeys, that would work, because it should then also revert the insert into the users table, because of the atomic property of the transaction. However, I do not know any ways to make the INSERT fail if the secondary key exists. If I add IF NOT EXISTS to the second insert, it will not revert the trasaction it will just avoid inserting into user_secondarykeys, but it will still insert into users.
Since Cassandra 2.0.6 you can use a conditional statements inside a batch, and if any of conditions will be not met then all instructions in that batch won't fire. This sounds great but there is a limitation - all of the statements inside batch have to operate on the single, same partition. According to this, it is impossible to make cross partition/table conditional insert/update/delete. So in your case this:
BEGIN BATCH
INSERT INTO users (userid, name, secondarykeys) VALUES (77059e45-5fac-460b-9c4f-47528c292be0, "Andreas", {'mail:andreas#example.org'});
INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas#example.org', 77059e45-5fac-460b-9c4f-47528c292be0) IF NOT EXISTS;
APPLY BATCH;
would not even pass the query validation, because you try here to operate on two different tables.
I'm not sure if this will be suitable for other of your requirements, I would need more information about your queries and the velocity/volume of the data. For sure there are other ways for modeling this.
It would greatly simplify the problem if every user would have to have at least one specified secondary key(e.g. email would be a great unique key for your users table), but that's are your requirements, so unless you can't change them there is no discussion.
Hope this will help you a bit.
Good luck!

How can I obtain the database schema from an existing ActiveRecord.cs file?

I have been given the source code for an existing project that uses SubSonic ORM. My (limited!) understanding is that SubSonic generates code by reverse-engineering the existing database. Unfortunately I don't have the database that was used for this project.
I do have the ActiveRecord.cs file from the last time it was compiled. How could I work out the database schema so I can reproduce the database?
This sounds like SubSonic 3. Here are a couple places to get you started based on me looking through my ActiveRecord.cs file. You might want to create a small database yourself, run SubSonic on it, and see what gets generated in ActiveRecord.cs.
Inside your ActiveRecord.cs file, you'll find one partial class per table. The partial class will inherit from IActiveRecord and will likely be the name of the table.
Inside the class, you'll find a function called "KeyName()" which will return your primary key column name for the table. SubSonic requires a primary key for tables it processes and generates code for.
Look for a region named " Foreign Keys ". If this table has foreign keys, you'll find a property corresponding to each foreign key, something like "public IQueryable OtherTableNames". So this table should have a column named something like "OtherTableNameID"; check the generated partial class for the foreign key table to be sure.
Immediately below the foreign key region, you'll find properties for the non-foreign key columns of this table. You can somewhat guess at the data types of the columns from the property data types (e.g. string might be a char(x) or a varchar(x)).

Resources