Google App Engine数据存储区:如果父密钥未知,如何按ID /名称获取实体?

时间:2013-01-13 08:38:43

标签: google-app-engine google-cloud-datastore

有两种实体:用户和旅行。用户是Trip的父级,Trip是用户的子级。

出于隐私考虑,我只发布旅行ID /姓名。因为它看起来像Trip Trip包含编码的用户ID /名称。

如果父密钥未知,如何按ID /名称获取实体?

5 个答案:

答案 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:id。 >

entity.getKey().toUrlSafe()

因此,在从实体到对象的转换中,分配Task元素,此ID在base-64 encode中编码。要从网址安全使用

返回密钥
Key.fromUrlSafe

它将保证您将始终使用全球唯一ID。

----第三种选择----

使用HATEOAS,您可以指定用于访问Task的链接,因此,如果任务具有某些ID,例如parentIduserId,那么基本上是获取其父节点& #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: {}  
       }
    }