Ответ 1
Вы не можете. Родительский ключ является частью ключа сущности, и для получения объекта требуется полный ключ.
Также запрос с ключевым фильтром не будет содержать сущности с родителями, если вы не укажете ключ предка.
Существует два типа сущности: "Пользователь и поездка". Пользователь является родителем Trip и Trip является дочерним для пользователя.
Для рассмотрения конфиденциальности я отправляю только идентификатор поездки/имя. Поскольку он похож на ключ отключения, он содержит кодированный идентификатор пользователя/имя.
Как получить объект по ID/имени, если родительский ключ неизвестен?
Вы не можете. Родительский ключ является частью ключа сущности, и для получения объекта требуется полный ключ.
Также запрос с ключевым фильтром не будет содержать сущности с родителями, если вы не укажете ключ предка.
Если вы создадите все свои "Пользовательские" сущности под сущностью "Root" и добавите свойство "uuid" в свой объект "Поездка", вы можете найти одно "Поездку" с указанным UUID.
Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);
@peter-knego В начальном вопросе: Пользователь является родителем для поездки. Чтобы получить объект по идентификатору, вам нужно восстановить ключ с родителем, чтобы получить полный ключ. Но вы можете избежать этого, просто выделите идентификаторы для полного ключа Trip. И вы можете построить полный ключ с выделенным идентификатором. Это моя логика.
Вы можете сделать что-то вроде этого:
public Entity GetEntity(String kind, String idName)
throws EntityNotFoundException{
Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
return datastore.get(key);
}
Я разработал 3 альтернативы, которые могут решить эту проблему, что очень важно IMHO.
---- 1-ая альтернатива ----
Если ваш идентификатор поездки рассчитан из другого атрибута, есть способ. Вместо того, чтобы получить Trip
своим id
, получить его из этого другого вычисленного свойства. Представьте, что ваш идентификатор поездки вычисляется по каноническому имени (A 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
), но вместо того, чтобы показывать, что id
, вы можете использовать безопасный идентификатор URL:
entity.getKey().toUrlSafe()
поэтому при преобразовании объекта в объект присваиваем элемент Task
этот код, закодированный в base-64 encode. Чтобы вернуть ключ из безопасного использования URL,
Key.fromUrlSafe
Это гарантирует, что вы всегда будете использовать глобальный уникальный идентификатор.
---- Третья альтернатива ----
Используя HATEOAS, вы можете указать ссылку для доступа к Task
, поэтому, если задача имеет некоторый идентификатор, такой как parentId
или userId
, который в основном получает родительский node id, вам может быть очень легко установить ссылку, указывающую на URL-адрес, подобный этому
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
}
}
}
Если вместо 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: {}
}
}