我应该如何在一个宁静的服务中设计一个有序列表资源?


11

我一遍又一遍地遇到了同样的问题,但我还没有找到我真正认为是最佳的解决方案。

在应用中说,您有一个有序列表,然后让用户通过拖放等方式更改该顺序。您希望顺序中的更改得以保留。您如何建模?

如何设计有序列表资源的静态服务?

特别是,我应该如何设计listitem宁静的资源的模型?我见过的最常见的设计是item具有orderposition属性的实体。我听到的另一种方法是在商品上使用双链表。

什么是一种方法,它不会向数据库写入太多内容,并且通常可以为客户端快速更新和读取?端点应该如何暴露?


出于好奇,为什么专门返回有序列表很重要?
亚当·威尔斯

好吧,我想我并不是特别希望返回有序列表资源,而是持久保留资源的顺序/位置,该资源可以是实际列表资源的一部分,也可以是隐式一部分。我想说的是让用户更改待办事项列表中待办事项的顺序。但是,无论有什么顺序重要的清单。我找不到设计这种方法的好方法
Rico Kahler

Answers:


14

表示有序列表是关系数据库的难题之一。将位置属性添加到列表成员关系是最常见的方法,因为您可以通过添加ORDER BY position到SQL查询中轻松地检索有序列表,并且可以通过平均假定位置是浮点数而不是整数,则此列表成员的上一个和下一个列表成员的值。

应避免使用双向链表,因为很容易意外使链接不一致,并最终以循环图或树结尾。

但是,RESTful API不受关系数据库的限制。您可以做一些自然的事情,而不是使用位置属性之类的技巧。

如果列表中最多只有几百个元素,则只需在请求中传输整个列表即可。假设我们要重新排序[1, 2, 3, 4]列表成员是ID的位置,我们可以

POST /url/of/the/list
Content-type: application/json
...

[1, 2, 4, 3]

然后,后端可以将其转换为您正在使用的任何数据库技术,但是API用户不必考虑这些细节。

如果列表很大,并且通常需要单独请求项目,则可以在url中允许索引:

GET /page/7

如果您喜欢HATEOAS,则响应中可以包含prev / next链接,以简化导航(如果通常这样消耗资源)。但是,这不一定意味着您的数据库也包含此双向链接列表。

如果该列表是非常大的,你可能要暴露ArrayList般的操作,如insertpush/ append。我可以想像一个电话

POST /url/of/the/list?at=1357;mode=insert
...

description of the item to insert

如果重新排序是常见的用例,并且应该立即提交重新排序,则可以在API中提供适当的终结点:

POST /url/of/the/list/reorder-item?from=783;to=1357

如果应该显式提交重新排序的列表,则将新订单作为JSON文档传输会更加容易,请参见上文。

现在并不是完全可以将您的API与正在使用的数据库技术分开查看。但是,最好使外部API不受实现细节的影响。如果有任何重新排序触及到约30行,只是为了更新整数列,那没什么大不了的。只要做最简单的事情,就总是更新整个列表。如果您的规模要求数据库使用更加复杂,则最好在后端维护这种复杂性,因为后端更易于保持一致性。


1
请注意,如果有多个客户端进行更改,则“替换整个列表”方法可能会出现问题。如果您不采取任何预防措施,最终可能会覆盖别人的更改(“最后写出胜利”)。
oefe

如果参数(at,from,to)是id,而不是列表索引,则类似列表的操作应该不会出现此问题
oefe

2

我认为不同方法的可行性在很大程度上取决于所使用的基础数据库。

此方法建议按顺序移动项目:

POST / url / of / the / list / reorder-item?from = 783; to = 1357

除非您具有SERIALIZABLE事务性,否则这可能会受到竞争条件的影响。大多数数据库中的默认级别READ_COMMITTED不会消除竞争条件!

我实际上认为,在大多数情况下(只要列表相对较小),那么replace-full-list方法就不会出现竞争状况问题,并且不会破坏数据。如果自客户提出请求以来项目集已更改,则可以返回409(冲突)。

它遭受了最后一次写入的胜利,但是对于任何api来说都是如此。无论您要实现哪种API,在查看页面时,其他客户端都可能已更新了该内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.