CosmosDB Graph:“upsert”查询模式

Posted

技术标签:

【中文标题】CosmosDB Graph:“upsert”查询模式【英文标题】:CosmosDB Graph : "upsert" query pattern 【发布时间】: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 查询?

提前致谢。

【问题讨论】:

【参考方案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 更难理解。由于需要副作用构造,您还会在遍历时产生额外的处理和内存成本,这可能是尝试避免它们的更多原因。

以上是关于CosmosDB Graph:“upsert”查询模式的主要内容,如果未能解决你的问题,请参考以下文章

Azure CosmosDB (16) 通过REST API对CosmosDB进行跨分区查询

用$ set和$ upsert更新mongodb

如何在 CosmosDB 中使用 Join 操作/子查询

如何在 CosmosDB 上查询最近 30 天?

SQL Server 同一查询中的多个计数 - CosmosDB

Azure CosmosDB (13) CosmosDB数据建模