【问题标题】:CosmosDB Graph : "upsert" query patternCosmosDB Graph:“upsert”查询模式
【发布时间】:2018-09-20 08:32:15
【问题描述】:

我是 Gremlin 查询语言的新手。 我必须在 Cosmos DB 图上插入数据(使用 Gremlin.Net 包),无论图中是否已经存在顶点(或边缘)。如果数据存在,我只需要更新属性。 我想使用这种模式:

g.V().hasLabel('event').has('id','1').tryNext().orElseGet {g.addV('event').has('id','1')}

但 Gremlin.Net / Cosmos DB 图形 API 不支持它。有没有办法在单个查询中进行一种 upsert 查询?

提前致谢。

【问题讨论】:

    标签: azure-cosmosdb gremlin


    【解决方案1】:

    有很多方法可以做到这一点,但我认为 TinkerPop 社区普遍采用这种方法:

    g.V().has('event','id','1').
      fold().
      coalesce(unfold(),
               addV('event').property('id','1'))
    

    基本上,它使用has() 查找“事件”并使用fold() 步骤强制到一个列表。该列表要么为空,要么包含Vertex。然后使用coalesce(),它会尝试unfold() 列表,如果它有一个Vertex,否则会立即返回,它会执行addV()

    如果想法是在找到元素后更新现有属性,只需在coalesce() 之后添加property() 步骤:

    g.V().has('event','id','1').
      fold().
      coalesce(unfold(),
               addV('event').property('id','1')).
      property('description','This is an event')
    

    如果您需要知道返回的顶点是否是“新的”,那么您可以执行以下操作:

    g.V().has('event','id','1').
      fold().
      coalesce(unfold().
               project('vertex','exists').
                 by(identity()).
                 by(constant(true)),
               addV('event').property('id','1').
               project('vertex','exists').
                 by(identity()).
                 by(constant(false)))
    

    关于这个主题的更多阅读可以在这个问题上找到:“Why do you need to fold/unfold using coalesce for a conditional insert?

    另请注意,此处描述了可选的边缘插入:“Add edge if not exist using gremlin”。

    最后一点,虽然这个问题是关于 CosmosDB 的,但答案通常适用于所有启用 TinkerPop 的图。当然,图如何优化这个 Gremlin 是一个单独的问题。如果图具有原生 upsert 功能,则该功能可能会或可能不会在此 Gremlin 的幕后使用,因此可能有更好的方法通过图系统原生 API 实现 upsert(当然,选择该路径会降低你的代码)。

    【讨论】:

    • 如果我希望查询也告诉我节点是已经存在还是刚刚创建,该怎么办?到目前为止我想出的是:g.V('1234').fold().as('existing').coalesce(unfold(), addV().property(id,'1234')).as('result').select('existing','result'),它工作得很好,返回{ 'existing': [], result: { ... } }创建节点时,但如果节点已经存在,则复制返回的有效负载:{ 'existing': [{ /*node payload*/ }], result: { /*same node payload again*/ } }
    • 我想我找到了更好的方法(刚刚了解了store()):g.V('1235').fold().store('existing').coalesce(unfold(), addV().property(id,'1235').store('new')).cap('existing','new')。这样,“现有”或“新”始终为空。让我知道是否有更好的方法来公开负载的布尔标志和单个属性。
    • 你的方法很好,但如果可以的话,避免副作用也很好。用无副作用的遍历和一个简单的布尔值更新了我的答案,作为是否添加顶点的返回值。
    • 太好了!谢谢你的分享。如何避免副作用?这是由于对函数式编程的纯粹性的哲学追求,还是它有可测量的、嗯、副作用?
    • 从左到右阅读 Gremlin 很好,而不必回溯到遍历中的某个较早点,因此从可读性的角度来看,我倾向于认为副作用使 Gremlin 更难理解。由于需要副作用构造,您还会在遍历时产生额外的处理和内存成本,这可能是尝试避免它们的更多原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-31
    • 2011-11-12
    • 2021-09-22
    • 2019-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多