DataStax Academy FAQ

DataStax Academy migrated to a new learning management system (LMS) in July 2020. We are also moving to a new Cassandra Certification process so there are changes to exam bookings, voucher system and issuing of certificates.

Check out the Academy FAQ pages for answers to your questions:


question

josef.schauer_169242 avatar image
josef.schauer_169242 asked ·

DSE 6.8: How to add/delete properties (UDT) which are in set

Hello,

I have the following setup

schema

schema.type('names')
  .ifNotExists()
  .property('property_id', UUID)
  .property('value', Text)
  .property('classification_ids', listOf(UUID))
  .create()
  
schema.type('hairColor')
  .ifNotExists()
  .property('property_id', UUID)
  .property('value', Text)
  .property('classification_ids', listOf(UUID))
  .create()
  
  schema.type('height')
  .ifNotExists()
  .property('property_id', UUID)
  .property('value', Integer)
  .property('classification_ids', listOf(UUID))
  .create()
 
schema.vertexLabel('Person').ifNotExists()
.partitionBy('person_id', UUID)
.property('names', setOf(typeOf('names')))
.property('hairColor', setOf(typeOf('hairColor')))
.property('height', setOf(typeOf('height')))
.create()
 
schema.vertexLabel('Person').searchIndex().ifNotExists().by('names').create()
schema.vertexLabel('Person').searchIndex().ifNotExists().by('hairColor').create()
schema.vertexLabel('Person').searchIndex().ifNotExists().by('height').create()

data

g.addV('Person')
.property('person_id', UUID.randomUUID())
.property('names', [ [ property_id: UUID.randomUUID(), value:'Name1', classification_ids: [UUID.randomUUID()] as List] as names] as Set)

questions

How to add a second names instance to properties?

  • it's not possible to use property(...) again, because this would overwrite the first added instance?

How to delete a specific names property instance, defined by "property_id"?

Thanks in advance

Josef

dsegraphuser-defined type
10 |1000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

pydebrito avatar image
pydebrito answered ·

Hi,

It is possible in gremlin to retrieve the collection, modify it (add or suppress elements in groovy) and save it back in the graph:

s = g.V().hasLabel('Person').has('person_id',UUID.fromString('9067e695-f4e5-4b23-8e74-7abce1e1feae')).values('names').unfold().toSet()
s.add(typeOf('name').create(UUID.randomUUID(),'Name1', Arrays.asList(UUID.randomUUID())))
s.remove(typeOf('name').create(UUID.fromString("467ee30c-f751-4de4-8f9a-2fa5a4a5d630"),'Name2', Arrays.asList(UUID.fromString("802e318d-9406-4ac8-8fd9-7278eb7ecedc")))) ;
g.V().hasLabel('Person').has('person_id',UUID.fromString('9067e695-f4e5-4b23-8e74-7abce1e1feae')).property('names', s) ;

Be careful of concurrent modifications though. If the names property is changed concurrently on the same person, the second change can override the first one (the write of one of the updates needs to be between the read and the write of the other update to create an issue)

2 comments Share
10 |1000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

I just changed your schema slightly suppressing the 's' from the UDT name, since there is just one name in the UDT :

schema.type('name')
  .ifNotExists()
  .property('property_id', UUID)
  .property('value', Text)
  .property('classification_ids', listOf(UUID))
  .create()

schema.vertexLabel('Person').ifNotExists()
.partitionBy('person_id', UUID)
.property('names', setOf(typeOf('name')))
.create()

schema.vertexLabel('Person').searchIndex().ifNotExists().by('names').create()


0 Likes 0 · ·

Brilliant!

0 Likes 0 · ·
karsten.stoehr avatar image
karsten.stoehr answered ·

Hi,

since in DSE 6.8 we can access the same data with Gremlin as well as with CQL I tried the following:

INSERT INTO traversals."Person" (person_id, names) VALUES (uuid(), {
  { property_id : uuid(), value : 'Donald', classification_ids : [ uuid(), uuid() ] }} );

This creates one Person vertex with in my example a person_id of 55ad46cd-96f3-4b73-b54f-6dbe5e46cd51. It also has a set of UDTs with one element that contains another uuid for property_id, the name 'Donald' and a list of UUIDs.

{
  "name": [
    "person_id",
    "names",
  ],
  "value": [
    "55ad46cd-96f3-4b73-b54f-6dbe5e46cd51",
    {
      "property_id": "b327be9e-1ba4-40c4-bb26-528bc080e7db",
      "value": "Donald",
      "classification_ids": [
        "d89ae42a-505d-431f-aa24-466e25f2dcdc",
        "7525105e-6bad-493c-a9c9-4e0b325d1cf1"
      ]
    }
  ],

Now we can update the same record (the vertex) to add another element to its set of name UDTs:

update traversals."Person" set names = names + { { property_id : uuid(), value : 'Mickey', classification_ids : [ uuid(), uuid() ] }} where person_id = 55ad46cd-96f3-4b73-b54f-6dbe5e46cd51;

Now we have two entries in the names set:

{
  "name": [
    "person_id",
    "names",
  ],
  "value": [
    "55ad46cd-96f3-4b73-b54f-6dbe5e46cd51",
  [
    {
      "property_id": "bcb1c193-5305-4949-8c88-98332dbc823d",
      "value": "Mickey",
      "classification_ids": [
        "90cb797a-2f74-4af7-8182-4ea7497fa9d3",
        "23e16534-5623-4927-a293-575546475e92"
      ]
    },
    {
      "property_id": "b327be9e-1ba4-40c4-bb26-528bc080e7db",
      "value": "Donald",
      "classification_ids": [
        "d89ae42a-505d-431f-aa24-466e25f2dcdc",
        "7525105e-6bad-493c-a9c9-4e0b325d1cf1"
      ]
    }
  ],

So the names column is a set and we add and remove entries to that set.

The elements of the set are UDTs that contain lists. Your question is how to add elements to the list of the UDT that is part of a set.

But sets allow only to append another object or to delete an object but it's not possible to update an existing object. Modifying the list within the UDT of the set's object is effectively an update of the set's object - which is not allowed.

Instead we need to delete the object from the set and then append the modified version of it to the set.

See also https://docs.datastax.com/en/cql-oss/3.3/cql/cql_using/useInsertSet.html for adding or removing an object from a set.

1 comment Share
10 |1000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

But this solution works only with CQL. In our case, It must be possible with gremlin, too.

I think if actions are possible with one API technology it should/must be supported also of the other technologies, in this case, gremlin.

0 Likes 0 · ·
bettina.swynnerton avatar image
bettina.swynnerton answered ·

Hi @josef.schauer_169242,

thank you again for your example schema and data, this makes studying your question so much easier.

If I understand you correctly here, you want to have several instances of the same property associated with the same vertex. We call this a multiple cardinality property, or multi-property in short.

This is not supported in DSE Graph 6.8, multi-properties are not supported, and multi-property schema cannot be created. Note that this is independent of the use of UDTs and applies to any vertex or edge property.

Does this answer your question?

2 comments Share
10 |1000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Hey @bettina.swynnerton,

I got this migration guide from one of your colleagues

Migration Guide

This guide contains the following part


I modeled the multi-property as Set like described, but how to work with these properties?

0 Likes 0 · ·
1596009990570.png (24.9 KiB)

Hi @josef.schauer_169242,

I am discussing with Karsten about this, and will do more research for you.

However, my understanding is that without the ability to define multiple cardinality properties in the schema, every insert to the property is an upsert and will overwrite the value.

Thanks for your patience while we look further into this.

0 Likes 0 · ·