Подтвердить что ты не робот

Хранилище данных Google App Engine: как получить объект по ID/имени, если родительский ключ неизвестен?

Существует два типа сущности: "Пользователь и поездка". Пользователь является родителем Trip и Trip является дочерним для пользователя.

Для рассмотрения конфиденциальности я отправляю только идентификатор поездки/имя. Поскольку он похож на ключ отключения, он содержит кодированный идентификатор пользователя/имя.

Как получить объект по ID/имени, если родительский ключ неизвестен?

4b9b3361

Ответ 1

Вы не можете. Родительский ключ является частью ключа сущности, и для получения объекта требуется полный ключ.

Также запрос с ключевым фильтром не будет содержать сущности с родителями, если вы не укажете ключ предка.

Ответ 2

Если вы создадите все свои "Пользовательские" сущности под сущностью "Root" и добавите свойство "uuid" в свой объект "Поездка", вы можете найти одно "Поездку" с указанным UUID.

Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);

Ответ 3

@peter-knego В начальном вопросе: Пользователь является родителем для поездки. Чтобы получить объект по идентификатору, вам нужно восстановить ключ с родителем, чтобы получить полный ключ. Но вы можете избежать этого, просто выделите идентификаторы для полного ключа Trip. И вы можете построить полный ключ с выделенным идентификатором. Это моя логика.

Ответ 4

Вы можете сделать что-то вроде этого:

public Entity GetEntity(String kind, String idName) 
        throws EntityNotFoundException{
    Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
    return datastore.get(key);
}

Ответ 5

Я разработал 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: {}  
       }
    }