克服 google 数据存储的 30 个子查询限制

Overcoming 30 sub-query limit for google datastore

Google datastore 开始时看起来很好,现在变得非常令人沮丧,但也许这只是我习惯了关系数据库。一般来说,我对数据存储和 nosql 还很陌生,并且进行了大量研究,但似乎无法找到解决此问题的方法。

假设我有一个用户 class 看起来像这样

class User{
  @Id
  Long id;
  String firstName, lastName; 
  List<Key<User>> friends;
}

我还有另一个 class 可以模拟用户已经完成的事件

class Event{
   Key<User> user;
   Date eventTime;
   List<Key<User>> receivers;
}

现在我要做的是查询我的朋友们完成的事件。 在通常的关系方式中,我会说:

select * from Event where user in (select friends from User where id = ?)

以此为起点我尝试了

// Key<User> userKey = ...
User user = ofy.load.type(User.class).key(userKey).first.now;
List<Key<User>> friends = user.getFriends();
ofy.load.type(Event.class).filter("user in", friends).order("-eventTime")list();

但我听说这个 30 个子查询的限制使它变得不可持续,因为我假设最终某人会有超过 30 个朋友,更不用说使用 'in' 子句将保证你无法将游标定位到继续加载事件。我做了很多研究并尝试了很多选择,但还没有找到解决这个问题的好方法,除了说 "why Google, why."

我考虑过的事情:

我真的很感激你能提供的任何意见,因为我 100% 没有想法

TL;DR ~ GAE 对 in-clause 可以处理的项目数量有限制,fml。

您来自关系数据库背景,所以非规范化的概念可能有点痛苦 - 我知道它适合我。

现在您有一个 table,其中包含来自所有用户的所有事件。这种方法在关系数据库中运行良好,但由于您提到的原因,在数据存储中是一场噩梦。

因此,要解决这个具体问题,您可以按如下方式重组数据:

  • 所有用户都有两条时间线。一份来自他们自己的帖子,一份来自朋友的帖子。 (public 内容可能有第三条时间线。)
  • 发布新事件时,它会写入创建它的用户的时间线,以及所有接收用户的时间线。 (您可能希望在用户的时间线中添加第三方时间线的引用,以便在用户决定删除事件时知道删除什么)

现在每个用户都可以访问完整的时间线,his/her自己的时间线和由第三方事件创建的时间线。这些时间线很容易查询,您根本不需要子选择。

这种方法有缺点:

  1. 写作成本较高。你必须写出比之前更多的时间线。您可能必须将其放入任务队列中,以便有足够的时间写入所有这些时间线。
  2. 您使用了更多的存储空间,但存储空间真的很便宜,我猜存储空间会比 运行 长期 运行 中昂贵的查询便宜。

尽管如此,您在 return 中得到的是通过这种反规范化对简单查询的快速响应。剩下的就是在 UI 中合并来自不同时间线的响应(您可以在服务器端进行,但我会在 UI 中进行)