【问题标题】:CosmosDB: Gremlin Query to create a new property using existing propertyCosmosDB:使用现有属性创建新属性的 Gremlin 查询
【发布时间】:2021-08-27 01:46:52
【问题描述】:

每个顶点都有一个结构:

{
    Id: 123,
    field1: 10
}

我想将field2 添加到所有顶点,使field2 的值等于field1

挑战在于,我在这里和其他地方发现的几乎所有查询都在 cosmos DB 中给出了语法错误。

例如

g.V().has("field1").property("field2", values("field1")) 

这会产生错误:Cannot create ValueField on non-primitive type GraphTraversal

请建议一个 cosmos DB 兼容查询(如果需要,多步)以在 DB 上执行此操作。 这是对 DB 的一次性操作,不会再次执行。

【问题讨论】:

    标签: graph azure-cosmosdb gremlin tinkerpop azure-cosmosdb-gremlinapi


    【解决方案1】:

    正如我在其他地方提到的,我不是 CosmosDB 专家,但我敢猜测你所问的问题无法用 CosmosDB 完成。您肯定拥有最简单形式的正确语法,因此更复杂的形式以某种方式解决问题的想法似乎不太可能。我想 property(String, Traversal) 目前根本不受支持,这意味着不可能进行就地更新。

    您可以测试复杂的表格(例如,select(Traversal,Traversal),如果您愿意的话,您可以自己满意 - 例如,从这个 blog post 演示如何从地图数据更新顶点:

    gremlin> m = [name:'marko',age:29,country:'usa']
    ==>name=marko
    ==>age=29
    ==>country=usa
    gremlin> g.withSideEffect('properties',m).
    ......1>   addV('person').as('vertex').
    ......2>   sideEffect(select('properties').
    ......3>              unfold().as('kv').
    ......4>              select('vertex').
    ......5>              property(select('kv').by(Column.keys), select('kv').by(Column.values)))
    ==>v[0]
    gremlin> g.V().has('person','name','marko').elementMap()
    ==>[id:0,label:person,country:usa,name:marko,age:29]
    

    因此,您唯一的办法是查询您希望更新的顶点,然后发送额外的遍历来更新您想要的字段。从结构上讲,这个建议是简单地以Map 形式检索数据,即键的顶点标识符和保存您希望移动的数据的值,然后简单地在返回的映射列表上使用 for 循环来发出按 id/value 查询:

    gremlin> g = TinkerFactory.createModern().traversal()
    ==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
    gremlin> data = g.V().has('age')
    ==>v[1]
    ==>v[2]
    ==>v[4]
    ==>v[6]
    gremlin> data = g.V().has('age').project('id','age').by(id).by('age').toList()
    ==>[id:1,age:29]
    ==>[id:2,age:27]
    ==>[id:4,age:32]
    ==>[id:6,age:35]
    gremlin> data.each { g.V(it['id']).property('personAge',it['age']).iterate() };[]
    gremlin> g.V().has('personAge').project('id','age').by(id).by('personAge')
    ==>[id:1,age:29]
    ==>[id:2,age:27]
    ==>[id:4,age:32]
    ==>[id:6,age:35]
    

    【讨论】:

    • 如果提供了另一个演示其工作原理的答案,我很乐意删除此答案。
    • 谢谢,斯蒂芬,我知道这个限制,但我正在寻找一个聪明的解决方案来解决这个限制。就像可能将 1 个查询的结果与映射到顶点 id 的每个节点的所有数据 field1 一起导出,然后以某种方式将此数据用于下一组查询以使用 field2 更新 DB 节点。这是数据库上需要的一次性操作。
    • 这就是我在最后一句话中的建议。让您的所有数据在查询中更新,然后遍历它并使用其他查询进行更新。我认为这是 CosmosDB 的唯一解决方案。
    • 您能否为这 2 个步骤提供经过测试的查询?
    • 我添加了一个示例,但我无法使用 cosmosdb 进行测试。我不知道 cosomosdb 对这种模式有问题。如您所见,这种方法确实没有什么特别之处。基本上以某种方式通过一个查询获取数据,然后使用每个返回值的查询对其进行循环以进行更新。