有两种实体:用户和旅行。用户是Trip的父级,Trip是用户的子级。
出于隐私考虑,我只发布旅行ID /姓名。因为它看起来像Trip Trip包含编码的用户ID /名称。
如果父密钥未知,如何按ID /名称获取实体?
答案 0 :(得分:18)
你做不到。父密钥是实体密钥的一部分,您需要一个完整密钥才能获得实体。
除非您指定祖先密钥,否则query with key filter将找不到包含父项的实体。
答案 1 :(得分:1)
如果您创建了所有"用户" " Root"下的实体实体并添加" uuid"属于您的旅行"旅行"实体,你可以寻找单身"旅行"使用指定的UUID。
Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);
答案 2 :(得分:0)
@ peter-knego在最初的问题:用户是Trip的父母。要通过id获取实体,您需要使用parent重建密钥以获取完整密钥。但是你可以避免这种情况,只需为Trip的全键分配id。并且您可以使用分配的id构造完整密钥。这是我的逻辑。
答案 3 :(得分:0)
您可以这样做:
public Entity GetEntity(String kind, String idName)
throws EntityNotFoundException{
Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
return datastore.get(key);
}
答案 4 :(得分:0)
我制定了3个可能解决这个问题的替代方案,这是一个非常重要的恕我直言。
----第一种选择----
如果您的旅行ID是根据其他属性计算出来的,那就有办法了。而不是从Trip
获取id
从其他计算属性获取它。让我们假设您的旅行ID由一些规范名称(您从其完整标题推断的URN)计算,例如,如果旅行的全名是
前往珠穆朗玛峰旅行
您的规范名称可能是voyage-to-the-everest
,这是您用作密钥名称的字符串。因此,不要使用datastore.get
获取元素,而是使用:
@Override
public Optional<Trip> findById(String tripCanonicalName) {
StructuredQuery.PropertyFilter eqTripCanonicalName = StructuredQuery.PropertyFilter
.eq("canonicalName", tripCanonicalName);
EntityQuery query = Query.newEntityQueryBuilder().setKind("Trip")
.setFilter(eqTripCanonicalName).setLimit(1).build();
QueryResults<Entity> results = getDatastoreService().run(query);
if (results.hasNext()) {
return Optional.of(fromEntity(results.next()));
}
return Optional.empty();
}
这将获得实体(Trip
),无论其父(User
)是谁。
----第二种选择----
在访问元素之前,您首先必须列出它们,然后选择一个并转到访问链接。我们知道使用任务的id不够,因为它仅对其父(User
)是唯一的,但是您可以使用url safe id:
entity.getKey().toUrlSafe()
因此,在从实体到对象的转换中,分配Task
元素,此ID在base-64 encode中编码。要从网址安全使用
Key.fromUrlSafe
它将保证您将始终使用全球唯一ID。
----第三种选择----
使用HATEOAS,您可以指定用于访问Task
的链接,因此,如果任务具有某些ID,例如parentId
或userId
,那么基本上是获取其父节点& #39; s id,你可以很容易地建立指向这样一个网址的链接
http://base-url.com/users/ {用户id} /任务/ {的TaskID}
因此,在HATEOAS请求中,这可以在链接中指示,指示元素的允许操作,因此查看元素时使用self
,例如
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"userId": "my-traveler-user-id",
"_links":{
"self":{
"href":"http://localhost:8080/users/my-traveler-user-id/tasks/voyage-to-the-everest
}
}
}
如果使用userId
代替parentId
,您可以使用所有节点指定是否有父级的接口来解决问题。即使它可以更灵活地使用parent
属性来定义整个父层次结构:
public interface DatastoreNode{
String getParentId();
String getParentKind();
String getParentUrlTag();
DatastoreNode getParent();
}
虽然强烈建议使用HATEOAS,但您可以推断出具有json结构的相同网址,例如
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"parent": {
parentKind: "User",
parentId: "my-traveler-user-id",
parentUrlTag: "users",
parent: {}
}
}