【发布时间】:2017-02-07 01:51:27
【问题描述】:
这是我一直在思考的一个问题,但我还没有编写任何代码,因为我首先想解决一些我正在努力解决的一般问题。这是主要的。
背景
单页网络应用程序向某个远程 API(在我们的控制之下)发出数据请求。然后它将这些数据存储在本地缓存中并从那里提供页面。理想情况下,应用在离线时仍能保持完整功能,包括创建新对象的能力。
约束
- 假设服务器端的产品数据库包含 +- 50000 个产品 (50Mb)
- 假设没有 db 类型,我们通过 REST/GraphQL 接口与之交互
- 假设单个产品记录
- 假设结果集的最大有效负载为 256kB
- 假设客户端最大存储空间为 5MB
- 假设每次搜索的搜索结果集介于 0 ... 5000 个项目之间
挑战
挑战在于定义一种无状态但(网络)有效的方式从结果集中获取页面,以便确定我们将获得哪些结果。
示例
在传统分页中,当使用此 url 获取某些查询的下 100 个结果时:
https://example.com/products?category=shoes&firstResult=100&pageSize=100
搜索结果可能如下所示:
{
"totalResults": 2458,
"firstResult": 100,
"pageSize": 100,
"results": [
{"some": "item"},
{"some": "other item"},
// 98 more ...
]
}
问题在于,根据这些信息,无法准确地获取特定页面上的对象。因为当我们请求下一页时,结果集可能已经改变(由于数据库的变化),影响了哪些项目是结果集的一部分。即使是很小的更改也会产生很大的影响:从数据库中删除的一个项目恰好位于结果集的第 0 页,这将改变我们在请求所有后续页面时将获得的结果。
目标
我正在寻找一种机制来使结果集的定义独立于未来的数据库更改,因此,如果有人在寻找鞋子并获得包含 2458 个项目的结果集,他实际上可以可靠地获取该结果集的所有页面即使它受到数据库后来更改的影响(我打算不真正删除项目,但为此目的在它们上设置一个已删除标志)
目前的想法
我看到了一个解决方案,其中结果集包含一个"pages" 属性,该属性是一个数组,其中包含该页面中项目的第一个和最后一个 id。假设您的 ID 数量不断增加,并且您并没有真正从数据库中删除项目,那么两个 ID 之间的项目数量是恒定的。这意味着应用程序可以获取这两个 ID 之间的所有项目,并始终获取完全相同的项目。此解决方案的问题在于,它仅在列表按 ID 顺序排序时才有效……我需要自定义排序选项。
我现在想出的唯一方法是只发送结果集中所有 ID 的列表...这样可以通过 SELECT * FROM products WHERE id IN (3,4,6,9,...) 获取页面...但这感觉相当不雅。 ..
我希望它不会太宽泛或太理论化。我有一个基于 Web 的数据库,只是不知道如何使用它进行分页。我正在寻找能够帮助我找到学习方向的答案,而不是完整的解决方案。
【问题讨论】:
-
我可能遗漏了一些东西,但是如果用户能够离线创建新对象,则索引不能是连续的(除非您对离线对象有不同的 id)。
-
通常人们不关心这些,只是获取项目,您的记录更新速度有多快,这会成为一个问题?
-
@fpg1503 系统将使用可以离线工作的分布式 ID 生成器。所以客户端在插入记录之前就知道记录的 ID。
-
我正在寻找的是一种捕获结果集的方法,使其随着时间的推移保持稳定。个别项目的内容可能会改变,但我不希望项目的顺序或集合中的哪些项目发生变化。这样做的原因是我以“无限滚动列表”的形式呈现项目,尽最大努力保持您拥有包含所有项目的列表的错觉,即使实际上只有一小部分在同时屏幕。查看bridalapp.com/wedding-dresses 以查看示例。我希望它扩展到 10.000 多个项目。
-
@fpg1503 我想直到现在我才理解您关于索引不是顺序的评论。你的意思是它不能保证只上升对吗?我想你是对的。我目前正在使用这个手卷发电机:ws.suid。服务器将 ID 块分发给客户端,它们可以在离线时缓存和使用。它会随着时间的推移而增加,但由于缓存的原因,可以在使用较高 ID 后使用较低 ID。看来我的问题比我想象的要多......
标签: algorithm pagination