Search code examples
javascriptgremlintinkerpopamazon-neptune

How to use Cardinality properly in mergeV in gremlin javascript?


I'm trying to set cardinality. It works with addV, for example

await g.V(id1).property(single, 'timestamp', 10).next();

However it does not work when I try to do it with mergeV

        const properties = new Map([
            ['prop1', CardinalityValue.single('prop1value3')],
            ['prop2', CardinalityValue.single('prop2value3')]
        ]);
        const propertiesNoCard = new Map([
            ['prop1', 'prop1value3'],
            ['prop2', 'prop2value']
        ]);

        await g
            .mergeV(
                new Map([
                    [t.label, 'test'],
                    [t.id, 'testid']
                ])
            )
            .option(onCreate, propertiesNoCard)
            .option(onMatch, properties)
            .iterate();
ResponseError: Server error: {"code":"UnsupportedOperationException","requestId":"408e6686-68dc-4700-b2c5-9d816d2a7bdb","detailedMessage":"Unsupported property value type: org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal","message":"Unsupported property value type: org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal"} (499)

I tried it this way because in gremlin source code's gremlin-javascript/test/cucumber/gremlin.js there's some examples where they call CardinalityValue.xxx, https://github.com/apache/tinkerpop/blob/master/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js

function({g}) { return g.mergeV(new Map([["name","marko"]])).option(Merge.onMatch,new Map([["age",CardinalityValue.single(33)]])) }

It does work if I declare it this way, gotten from Gremlin MergeV To Update an Existing Element's property and Single Cardinality

        const properties = new Map([
            ['prop1', CardinalityValue.single('prop1value3')],
            ['prop2', CardinalityValue.single('prop2value3')]
        ]);
        const propertiesNoCard = new Map([
            ['prop1', 'prop1value3'],
            ['prop2', 'prop2value']
        ]);

        await g
            .mergeV(
                new Map([
                    [t.label, 'test'],
                    [t.id, 'testid']
                ])
            )
            .option(onCreate, propertiesNoCard)
            .option(
                onMatch,
                __.sideEffect(__.property(single, 'prop1', 'prop1val23').property(single, 'prop2', 'prop2val23')).constant(
                    new Map()
                )
            )
            .iterate();

Solution

  • From the tags it looks as if you may be using Amazon Neptune. The support for cardinality the way you are using it was added to Apache TInkerPop in release 3.7.0. Amazon Neptune currently supports TinkerPop at the 3.6.2 level. Until Amazon Neptune moves up to the 3.7.x TinkerPop versions you might be able to use the following example pattern as a workaround. This was tested using Amazon Neptune at the 1.2.1.0.R6 engine version. The example is written as basic Gremlin but you should be able to adopt this in your Javascript code.

    g.mergeV([(T.id): 'test-1234', (T.label) : 'Test']).
        option(onCreate, ['name': 'name1']).
        option(onMatch, sideEffect(property(single,"name","name2")).constant([:]))
    

    Which the first time creates

    g.V('test-1234).valueMap(true)
    
    {<T.label: 4>: 'Test', 'name': ['name1'], <T.id: 1>: 'test-1234'}
    

    Then if we run the merge above a second time and check the vertex, the update has been applied in a single cardinality fashion.

    g.V('test-1234).valueMap(true)
    {<T.label: 4>: 'Test', 'name': ['name2'], <T.id: 1>: 'test-1234'}