Google App Engine Datastore:如果父键未知,如何通过 ID/名称获取实体?
Posted
技术标签:
【中文标题】Google App Engine Datastore:如果父键未知,如何通过 ID/名称获取实体?【英文标题】:Google App Engine Datastore: How to get entity by ID/Name if parent key is unknown? 【发布时间】:2012-12-27 10:31:21 【问题描述】:有两种实体:User 和 Trip。 User 是 Trip 的父级, Trip 是 User 的子级。
出于隐私考虑,我只发布旅行 ID/名称。因为它看起来像旅行钥匙包含编码的用户 ID/名称。
如果父键未知,如何通过 ID/名称获取实体?
【问题讨论】:
+1 - 这是一个完全有效的问题。谁把 -1 - 解释一下? 为什么不使用搜索? [见][1] [1]:***.com/questions/12675664/… @Lapteuh - 你有没有看过你所指的答案?他们提出的查询需要完整的父键(种类+id/名称),而这正是 OP 所没有的。 那么,我们该怎么办?将键值发送给客户端并使用该键检索对象? @nurp 我认为应该将用户 ID 存储在会话中,然后将旅行 ID 传递给客户端。因此,当客户端想要更新行程时,会将行程 ID 发送回服务器,然后服务器从会话中获取用户 ID,以创建完整的行程密钥。例如: Key userKey = KeyFactory.createKey(TABLE_USER, userId);密钥tripKey = KeyFactory.createKey(userKey, TABLE_TRIP, tripId); 【参考方案1】:我想出了 3 个可以解决这个问题的替代方案,恕我直言,这是一个非常重要的替代方案。
---- 第一种选择----
如果您的行程 ID 是根据其他属性计算的,则有一种方法。而不是通过其id
获取Trip
,而是从其他计算属性中获取它。假设您的 Trip 的 id 是由某个规范名称(您从其完整标题推断出的 URN)计算的,例如如果 Trip 的全名是
珠穆朗玛峰之旅
您的规范名称可能是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();
无论父 (User
) 是谁,这都会获取实体 (Trip
)。
---- 第二种选择----
在访问一个元素之前,您可能首先必须列出它们,然后选择一个并转到访问链接。正如我们所知,使用任务的 id 是不够的,因为它仅对其父级 (User
) 是唯一的,但您可以使用 url 安全 id 而不是显示 id
:
entity.getKey().toUrlSafe()
所以在从实体到对象的转换中,分配Task
元素,这个id 在base-64 encode 中编码。要从 url 安全使用中取回密钥
Key.fromUrlSafe
它将保证您将始终使用全局唯一 ID。
---- 第三种选择----
使用HATEOAS可以指定访问Task
的链接,所以如果任务有一些id,比如parentId
或userId
,这基本上是获取他的父节点的id,这可能很容易你建立一个指向这样的网址的链接
http://base-url.com/users/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
如果您使用parentId
而不是userId
,则可以使用所有节点指定是否有父节点的接口来解决。使用parent
属性甚至可以更灵活地定义整个父层次结构:
public interface DatastoreNode
String getParentId();
String getParentKind();
String getParentUrlTag();
DatastoreNode getParent();
虽然强烈建议使用 HATEOAS,但您可以推断出具有 json 结构的相同 url,例如
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"parent":
parentKind: "User",
parentId: "my-traveler-user-id",
parentUrlTag: "users",
parent:
【讨论】:
【参考方案2】:你不能。父键是实体键的一部分,您需要一个完整的键来获取实体。
除非您指定祖先键,否则 query with key filter 也不会找到具有父级的实体。
【讨论】:
【参考方案3】:你可以这样做:
public Entity GetEntity(String kind, String idName)
throws EntityNotFoundException
Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
return datastore.get(key);
【讨论】:
不,除非您在key
中指定父级,否则它不会找到任何东西。【参考方案4】:
如果您在“根”实体下创建所有“用户”实体并向“旅行”实体添加“uuid”属性,则可以查找具有指定 UUID 的单个“旅行”。
Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);
【讨论】:
【参考方案5】:@peter-knego 在最初的问题中:用户是 Trip 的父母。要通过 id 获取实体,您需要使用父项重建密钥以获取完整密钥。但是您可以避免这种情况,只需为 Trip 的完整密钥分配 id。您可以使用分配的 id 构造完整的密钥。这是我的逻辑。
【讨论】:
以上是关于Google App Engine Datastore:如果父键未知,如何通过 ID/名称获取实体?的主要内容,如果未能解决你的问题,请参考以下文章
Google Cloud 中的 Google Compute Engine、App Engine 和 Container Engine 有啥区别?
连接 Google App Engine 和 Google Compute Engine
Google App Engine Flexible 和 Google Container Engine 之间的区别?
如何在 Google Cloud App Engine 上使用 PubSub 创建订阅者,该订阅者通过 Publisher 从 Google Cloud App Engine Flex 收听消息?