question

josef.schauer_169242 avatar image
josef.schauer_169242 asked josef.schauer_169242 commented

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

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 josef.schauer_169242 commented

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)

5 comments Share
10 |1000

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 commented ·

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 ·
karsten.stoehr avatar image karsten.stoehr commented ·

Brilliant!

0 Likes 0 ·
josef.schauer_169242 avatar image josef.schauer_169242 karsten.stoehr commented ·

How to delete something from the set if I know only the property id?

Could you please provide an example for that, too.


Thanks

0 Likes 0 ·
josef.schauer_169242 avatar image josef.schauer_169242 josef.schauer_169242 commented ·

It seems that minus on set is working


g.V().hasLabel('Person').has('person_id',eq(UUID.fromString('9067e695-f4e5-4b23-8e74-7abce1e1feae')))
.property('names', values('names').toSet().minus(values('names').toSet().flatten().find { it.getUUID("property_id").equals(UUID.fromString('ded0511d-0577-4882-bff7-dcbb32fccbd8'))}))


but plus it not working in a one-liner.

0 Likes 0 ·
josef.schauer_169242 avatar image josef.schauer_169242 commented ·

@pydebrito @karsten.stoehr


Is it possible to do it in one query?

like this:

g.V().hasLabel('Person').has('person_id',UUID.fromString('9067e695-f4e5-4b23-8e74-7abce1e1feae')).property('names', values('names').unfold().toSet() + typeOf('name').create(UUID.randomUUID(),'Name1', Arrays.asList(UUID.randomUUID()))) ;


In my tests, it was not possible. It is very important for our use case.

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

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

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

josef.schauer_169242 avatar image josef.schauer_169242 commented ·

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)
bettina.swynnerton avatar image bettina.swynnerton ♦♦ josef.schauer_169242 commented ·

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 ·
karsten.stoehr avatar image
karsten.stoehr answered josef.schauer_169242 commented

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

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

josef.schauer_169242 avatar image josef.schauer_169242 commented ·

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 ·