Google app engine Google应用程序引擎数据存储:如果父密钥未知,如何通过ID/名称获取实体?
有两种实体:用户和旅行。用户是Trip的父级,Trip是用户的子级 出于隐私考虑,我只发布旅行ID/姓名。因为它看起来像一个Trip密钥包含编码的用户ID/名称Google app engine Google应用程序引擎数据存储:如果父密钥未知,如何通过ID/名称获取实体?,google-app-engine,google-cloud-datastore,Google App Engine,Google Cloud Datastore,有两种实体:用户和旅行。用户是Trip的父级,Trip是用户的子级 出于隐私考虑,我只发布旅行ID/姓名。因为它看起来像一个Trip密钥包含编码的用户ID/名称 如果父项未知,如何按ID/名称获取实体?您不能。父键是实体键的一部分,需要完整键才能获取实体 除非您指定祖先密钥,否则也找不到具有父项的实体。@peter knego在初始问题中:用户是Trip的父项。若要按id获取实体,您需要使用父项重构密钥以获取完整密钥。但您可以避免这种情况,只需为行程的完整密钥分配ID即可。您可以使用分配的id构
如果父项未知,如何按ID/名称获取实体?您不能。父键是实体键的一部分,需要完整键才能获取实体
除非您指定祖先密钥,否则也找不到具有父项的实体。@peter knego在初始问题中:用户是Trip的父项。若要按id获取实体,您需要使用父项重构密钥以获取完整密钥。但您可以避免这种情况,只需为行程的完整密钥分配ID即可。您可以使用分配的id构造完整密钥。这是我的逻辑 如果在“根”实体下创建所有“用户”实体,并将“uuid”属性添加到“Trip”实体中,则可以查找具有指定uuid的单个“Trip”
Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);
您可以这样做:
public Entity GetEntity(String kind, String idName)
throws EntityNotFoundException{
Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
return datastore.get(key);
}
我制定了3个备选方案来解决这个问题,这是IMHO非常重要的一个 ----第一个备选方案-- 如果您的旅行Id是根据另一个属性计算的,那么有一种方法。不要通过其
id
获取Trip
,而是从其他计算属性获取它。让我们假设您的旅行id是由某个规范名称(您从其全名推断出的URN)计算的,例如,如果旅行的全名是
珠穆朗玛峰之旅
您的标准名称可能是珠穆朗玛峰之旅
,这是您用作钥匙名称的字符串。因此,不要使用数据存储获取元素。获取使用:
@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();
}
因此,在从实体到对象的转换中,分配任务
元素,该id编码为。要从url获取密钥,请安全使用
Key.fromUrlSafe
它将保证您将始终使用全球唯一id
----第三种备选方案--
使用可以指定用于访问任务的链接
,因此,如果任务具有某种id,例如parentId
或userId
,基本上是获取其父节点的id,则可以很容易地建立指向如下url的链接
{userId}/tasks/{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,但您可以推断相同的url具有json结构,例如
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"parent": {
parentKind: "User",
parentId: "my-traveler-user-id",
parentUrlTag: "users",
parent: {}
}
}
+这是一个完全正确的问题。谁放了-1-来解释一下?你为什么不使用搜索?[见][1][1]:@Lapteuh-你有没有看过你提到的答案?他们提出的查询需要完整的父键(kind+id/name),而这正是OP所没有的。那么,我们该怎么办呢?将键值发送给客户端并检索具有该键值的对象?@nurp我认为应该发生的是将用户ID存储在会话中,然后将Trip ID传递给客户端。因此,当客户机想要更新trip时,trip ID被发送回服务器,然后服务器从会话中获取用户ID,以创建完整的trip密钥。例如:Key userKey=KeyFactory.createKey(表\用户,用户ID);Key-tripKey=KeyFactory.createKey(userKey,TABLE\u TRIP,tripId);不,除非您在键中指定父项,否则它不会找到任何内容。
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"parent": {
parentKind: "User",
parentId: "my-traveler-user-id",
parentUrlTag: "users",
parent: {}
}
}