我无法理解如何构建具有多个死者的祖先树。假设我有一个这样的模型(每个实体都有一个Long id
):
User
-Post
-Comment
Comment
是User
的孙子。
真正令人烦恼的是插入Comment
我需要生成Post
的密钥。要生成Post
的密钥,我还需要知道User
的ID:
Key<Post> postKey = Key.create(Key.create(User.class, userId), Post.class, postId);
这对我来说是个问题,因为在尝试将注释插入数据存储区时,我还需要传入userId和postId来生成Post
的密钥。
同样,尝试获取一个帖子很烦人,因为我需要传入userId和postId以生成密钥。
我正在寻找一种更好的方法来构建我的模型和API方法,而无需将所有这些祖先ID传递给我的方法。我正在考虑将websafeKey存储在每个Post和Comment实体中,作为这样的属性:
String websafeKey = Key.create(Key.create(User.class, userId), Post.class, postId).getString();
Key<Post> key = Key.create(websafeKey);
然后,我可以在实体中找到每个帖子和评论(以及这些实体的其他孩子)的关键。然后我可能不必一直将所有祖先ID传递给我的API方法。
不确定这是不是一个好主意。
答案 0 :(得分:2)
根据提供的信息,您有两个选择:
注意:写完这一切之后,我意识到最终的API看起来都是一样的:
GET /user/{key} - get user info
POST /user/{key}/post/ - create post
GET /post/{key} - get post
POST /post/{key}/comment/ - create comment
GET /comment/{key}
在这种情况下,{key}是网络安全密钥。
优点:
在这种情况下,{key}是id,并且没有实体层次结构
拆卸/优点:
根据我的经验,你绝对应该做第一个选择,你可能会错误地使你的数据模型错误几次,并且能够改变/迁移它是绝对的胜利。
答案 1 :(得分:1)
首先,我同意Konqi说他应该仔细设计你的祖先/钥匙模型 考虑到写/秒的权衡,以获得您想要的正确级别的一致性 吞吐量。
假设您仍然想要用户 - &gt;发布 - &gt;评论设计,处理数据存储祖先 像这样的关键参考,我们得出了一个几乎相似的解决方案 你的想法。我们创建键的字符串表示。根据您的具体情况, 它会是:
/users/{userId}/posts/{postId}/comments/{commentId}
我们还有一个便利类型来封装该表示,称为IdRef<T>
。
每次从数据存储区检索实体时,我们都会构造此表示 对于每个API请求,我们都会从给定的字符串中翻译它。
使用这种方法,我们可以轻松地公开这样的API:
GET /users/{userId}/posts/{postId}/comments/{commentId}
POST /users/{userId}/posts/{postId}/comments/{commentId}
DELETE /users/{userId}/posts/{postId}/comments/{commentId}
我保留opensource project,除其他功能外,还解决了你提到的问题。 它是一个Java DSL,旨在从您的appengine数据存储模型中公开RESTful API。
如果您有兴趣,可以使用gist来举例说明您的用例。
答案 2 :(得分:0)
我遇到了同样的问题,并且目前已经实现了与@feroult类似的东西,尽管我仍在寻找更好的方法。让我解释一下这个决定背后的一些逻辑。
让我们假设我们读取了一些资源的列表,该资源在树中至少有几个级别。上面的“评论”示例可能是一个例子。在这种情况下,如果我们在客户端使用数据存储区,那么是的,我们的API将非常RESTful,因为密钥本身将包含到根实体的路径。但问题是这种方法效率低,因为每个键都会重复祖先路径。
另一种方法是在客户端上创建类似树的结构,类似于树,就像来自数据存储区的数据一样。如果我们想要用户做出的所有评论,那么我们只需要将用户id驻留在内存中一次。没有理由将其表示为每个评论的关键字。然后,这会导致我们在RESTful api中发送完整的祖先路径/ users / {userId} / posts / {postId} / comments / {commentId}。
在一天结束时,无论实际路径如何,必须将相同的信息传递到数据存储区。这很关键。没有祖先路径,Google Datastore无法找到评论。
这意味着问题可以简化为语义之一。也许妥协是创建一个等效的客户端密钥工厂,它可以从祖先id生成密钥,然后将其发送到服务器。在这种情况下,将避免重复,并且RESTful API仍然是干净的。
有兴趣听取其他想法。