中继突变:突变分页关联

Posted

技术标签:

【中文标题】中继突变:突变分页关联【英文标题】:Relay Mutations: Mutating Paginated Associations 【发布时间】:2017-07-13 00:24:24 【问题描述】:

在很多情况下,我们需要修改一对多或多对多关联,并且关联作为分页列表暴露给查询。

有一些关键要求:

客户端必须能够删除、添加和更新关联元素 在某些情况下,关联的顺序很重要,在这种情况下,客户端也必须能够重新排序元素

不太重要:

客户端应该能够在创建父项时指定关联(例如,在创建产品的同时创建一组有序的变体) 客户端应该能够通过某种形式的事务原子性一次性删除、添加、更新和重新排序关联元素 客户端不必为了添加或删除单个元素而对整个当前关联进行分页

这个问题有很多可能的解决方案:

选项 1 - 单个输入字段,无其他突变

输入类型有一个数组输入字段,表示关联的全部真实性(添加新元素,更新现有元素,删除缺失元素,并在必要时保留顺序)。

缺点:删除非常隐含。客户端必须对关联的整个当前状态进行分页。不是颗粒状的。

选项 2 - 带位置的单个输入字段,删除突变

输入类型有一个数组输入字段,用于更新现有元素和添加新元素(忽略缺失的元素)。可以在元素上指定位置或索引值以重新排序它们。单独的突变用于删除元素。

缺点:当所有其他操作都在父级上时,删除在突变中自行关闭是不一致的。不是很细。

选项 3 - 单个输入字段,删除和重新排序突变

输入类型有一个数组输入字段,用于更新现有元素和添加新元素(忽略缺失的元素)。单独的突变用于删除和重新排序元素。

缺点:客户无法将新元素添加到关联中的特定位置,它们必须单独添加然后重新排序。不是很细。

选项 4 - 单个输入字段,添加/删除/重新排序突变

与选项 3 一样,只是输入字段仅用于更新;单独的突变用于添加新元素。

缺点:客户端必须进行多次更改才能执行复杂的更新。客户端无法创建具有初始关联的父级。

选项 5 - 完全独立的突变

父输入类型没有相关字段,一切都是通过四个独立的添加/删除/更新/重新排序突变完成的。

优点:非常明确和细化,将不同的数据模型对象分开。 缺点:客户端必须进行多次更改才能执行复杂的更新。客户端无法创建具有初始关联的父级。

选项 6 - 两个带位置的输入字段

输入类型有两个数组字段:一个用于更新、添加和重新排序元素(请参阅选项 2),另一个用于删除。

缺点:感觉就像我们正在污染父突变;不是颗粒状的。

选项 7 - 两个输入字段,重新排序突变

与选项 6 类似,不同之处在于使用单独的重新排序突变而不是位置参数。

缺点:重新排序无法自行关闭。另请参阅选项 6 的缺点。

所有这些选项似乎都有缺点。选项 5 似乎是最明确的,但要求用户同时使用多个突变,其中操作不再是真正的原子。

Facebook 处理这些类型的突变的方式是什么?你的方法是什么?谢谢!

【问题讨论】:

【参考方案1】:

所有这些方法之间肯定存在权衡,因此选择一种方法真的取决于我试图构建的内容。

Facebook 架构中最常见的情况有两个很好的约束:

没有重新排序 没有批量操作

Facebook 上的评论是这里的典型示例。对于这样的情况,我们已经成功地使用了选项 5,我可以自信地推荐它。对于 cmets,我们只有三个突变; commentCreatecommentEditcommentDelete

对于这样的情况,我们最终得到了常见的模式:

对于createedit(或update)突变,突变解析为的对象通常包含已修改的edge(我使用edge 的含义与我们在Pagination Best Practice doc 中使用边缘)。然后,您可以从该边缘轻松获取修改后的对象...但您也可以获取任何可能需要的边缘数据。 deletemutations 通常只返回被删除对象的 ID;如果客户端在输入中提供了该 ID,这对客户端来说是一种纯粹的便利,但如果删除输入需要一些其他信息并且服务器将其转换为 ID,那么返回删除的 ID 允许客户端知道哪个对象被删除了。

选项 5 [...] 客户端无法创建具有初始关联的父级。

我不完全确定我是否遵循这一点;我的评论示例在这里没有一个很好的例子(因为它在产品中不存在),但假设如果我想发表评论同时回复该评论,我可以想象一下做这样的事情:

commentCreate(input: text:"Hello World", replies:[text:"Reply 1", text:"Reply 2"])

我重用了commentCreate 用作replies 接受的复数输入类型的输入类型。


对于需要重新排序或批量操作的情况,这听起来像是您正在查看的主要情况,我没有很好的答案,而且正如您所说,这绝对是一个更棘手的情况。我认为我没有看到足够多的例子来自信地推荐一个选项而不是另一个选项,而且我认为哪个选项最好最终可能取决于特定的用例。但是,要考虑的另一个选项是使用单个突变,其中输入是操作列表。因此,如果我们有一个“最喜欢的照片”列表并且我们想要进行批量更新,我们可以这样做:

favoritePhotosUpdate(operations: operation:ADD, addedId:1234, operation:REMOVE, addedId:5678, operation:UPDATE, oldId:4321, newId:8765, operation:SWAP, oldId:32, newId:76

不确定这实际上是否比上述选项更好,但这是我们过去讨论过的另一个选项(尽管我不确定我们是否已将其付诸实践),因此至少值得添加列表。

希望这会有所帮助!

【讨论】:

以上是关于中继突变:突变分页关联的主要内容,如果未能解决你的问题,请参考以下文章

进行后续突变后中继不更新

中继突变不能动态工作

使用中继环境的突变

中继项目中的更新突变问题

中继现代突变,RANGE_ADD / Append

如何在中继服务器中使用删除突变?