Reputation: 661
There are two kinds of entity: User and Trip. User is parent to Trip and Trip is child to User.
For privacy consideration I am POSTing only Trip ID/Name. Because it is looks like a Trip Key contains encoded User ID/Name.
How to get entity by ID/Name if parent key is unknown?
Upvotes: 26
Views: 11409
Reputation: 19
trip_query = datastore_client(kind='Trip')
trips = list(trip_query.fetch())
for trip in trips:
# .key.id_or_name
print(f'trip id/name:{trip.key.id_or_name}')
Upvotes: 0
Reputation: 12685
I worked out 3 alternatives that may solve this issue, which is a very important one IMHO.
---- 1st alternative ----
If your Trip's Id is calculated from another attribute, there is a way. Instead of getting the Trip
by its id
get it from that other calculated property. Let's imagine your Trip's id is calculated by some canonical name (A URN you infer from its full title), e.g. if the Trip's full name is
Voyage to the Everest
your canonical name may be voyage-to-the-everest
and this is the String you use as name for the Key. So instead of getting the element using datastore.get
use:
@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();
}
this will get the entity (Trip
) no matter whose parent (User
) be.
---- 2nd alternative ----
Before accessing an element probably you first have to list them and then select one and go to an access link. As we know using the id of the task wont be enough because it will be unique only for its parent (User
), but instead of showing that id
you may use the url safe id:
entity.getKey().toUrlSafe()
so in the conversion from entity to object assign the Task
element this id encoded in a base-64 encode. To get the key back from the url safe use
Key.fromUrlSafe
It will guarantee you will always gonna use a global unique id.
---- 3rd alternative ----
Using HATEOAS you can specify the link for accesing the Task
, so if the task has some id such as parentId
or userId
which is basically getting his parent node's id, it could be very easy for you to stablish a link pointing to a url like this
http://base-url.com/users/{userId}/tasks/{taskId}
So in a HATEOAS request this could be indicated in the links, that indicates the allowed actions for the element, so for viewing the element use self
, e.g
{
"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
}
}
}
If instead of a userId
you use a parentId
you may work it out with an interface where all the nodes specify if they have a parent or not. Even it could be more flexible with a parent
property where you define the whole parent hierarchy:
public interface DatastoreNode{
String getParentId();
String getParentKind();
String getParentUrlTag();
DatastoreNode getParent();
}
Although HATEOAS is strongly recommended you can infer the same url having a json structure such as
{
"id": "voyage-to-the-everest",
"name":"Voyage to the Everest",
"parent": {
parentKind: "User",
parentId: "my-traveler-user-id",
parentUrlTag: "users",
parent: {}
}
}
Upvotes: 0
Reputation: 80340
You can't. Parent key is part of the entity key and you need a full key to get an entity.
Also query with key filter won't find entities with parents unless you specify the ancestor key.
Upvotes: 19
Reputation: 1786
You can do something like this:
public Entity GetEntity(String kind, String idName)
throws EntityNotFoundException{
Key key = KeyFactory.createKey(kind, Long.parseLong(idName));
return datastore.get(key);
}
Upvotes: 0
Reputation: 1207
If you create all of your "User" entities under a "Root" entity and add a "uuid" property to your "Trip" entity, you can look for the single "Trip" with the specified UUID.
Filter uuidFilter = new FilterPredicate("uuid", FilterOperator.EQUAL, uuid.toString());
Query q = new Query("Trip").setAncestor(root.getKey()).setFilter(uuidFilter);
Upvotes: 1
Reputation: 117
@peter-knego In initial question: User is parent for Trip. To get entity by id you need reconstruct key with parent to get full key. But you may avoid this, just allocate ids for full key of Trip. And you may construct full key with allocated id. This is my logic.
Upvotes: 0