Key vs ID/Name? - google-app-engine

I do not want to create an autogenerated key for my entities so I specify my own:
Entity employee = Entity.newBuilder().setKey(makeKey("Employee", "bobby"))
.addProperty(makeProperty("fname", makeValue("fname").setIndexed(false)))
.addProperty(makeProperty("lname", makeValue("lname").setIndexed(false)))
.build();
CommitRequest request = CommitRequest.newBuilder()
.setMode(CommitRequest.Mode.NON_TRANSACTIONAL)
.setMutation(Mutation.newBuilder().addInsert(employee))
.build();
datastore.commit(request);
When I check to see what the entity looks like it looks like this:
Why is this auto-generated key generated if I specified my own key (bobby)? It seems bobby was also created, but now I have bobby and this autogenerated key. What is the difference between the key and id/name?

You can't specify your own key, keys actually contain information necessary for the datastore operation. This note in the documentation gives you an idea:
Note: The URL-safe string looks cryptic, but it is not encrypted! It
can easily be decoded to recover the original entity's kind and
identifier:
key = Key(urlsafe=url_string)
kind_string = key.kind()
ident = key.id()
If you use such URL-safe keys, don't use sensitive data such as email
addresses as entity identifiers. (A possible solution would be to use
the MD5 hash of the sensitive data as the identifier. This stops third
parties, who can see the encrypted keys, from using them to harvest
email addresses, though it doesn't stop them from independently
generating their own hash of a known email address and using it to
check whether that address is present in the Datastore.)
What you can specify is the ID portion of the key, either as a number or as a string:
A key is a series of kind-ID pairs. You want to make sure each entity
has a key that is unique within its application and namespace. An
application can create an entity without specifying an ID; the
Datastore automatically generates a numeric ID. If an application
picks some IDs "by hand" and they're numeric and the application lets
the Datastore generate some IDs automatically, the Datastore might
choose some IDs that the application already used. To avoid, this, the
application should "reserve" the range of numbers it will use to
choose IDs (or use string IDs to avoid this issue entirely).

This is the url-safe version of your key, suitable for use in links. Use KeyFactory.stringToKey to convert it to an actual key, and you'll see that it contains your string name.

What you create with makeKey("Employee", "bobby") is a key for an Entity with the entity name Employee and the name bobby. What you see as Key in the datastore viewer is a representation for exactly that.
Generally speaking a key always consists of
optional parent key (with entity type and name/id)
entity type
entity name/id
Maybe someone here can tell you how to decode the key into its components but rest asured that you're doing everything right and the behavior is as expected.

Related

Google App Engine (datastore) - will a deleted key regenerate?

I've got a simple question about datastore keys. If I delete an entity, is there any possibility that the key will be created again? or each key is unique and can be generated only one-time?
Thanks.
It is definitely possible to re-use keys.
Easy to test, for example using the datastore admin page:
create an entity for one of your entity models using a custom/specified key name and some property values
delete the entity
create another one using the same key name and different property values...
As for the keys with auto-generated IDs it is theoretically possible, but I guess rather unlikely due to the high number of possibilities. From Assigning identifiers:
Cloud Datastore can be configured to generate auto IDs using two
different auto id policies:
The default policy generates a random sequence of unused IDs that are approximately uniformly distributed. Each ID can be up to 16
decimal digits long.
The legacy policy creates a sequence of non-consecutive smaller integer IDs.

Is it secure to use database primary key values in API directly

I have a database which has particular table "Attribs" that contains a list of attributes for a user like name, address, phone number etc. each of which is the key. The REST API I have uses this table to get attribute name and fills up another table. However, the keys in "Attribs" are being exposed in API.
e.g. if I am trying to put user name which is an attribute user_name then my REST API will have a line like
"user_name":"abcd"
Is is safe to expose these keys or may it cause any possible security issues?
We don't have enough context but no, it is an insecure practice, and there is an entire section on OWASP about it. https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References It is a principle, do not directly expose IDs, but use and indirection layer.
Impacts in your case are not assessable with the description you provide, but I would apply the principle if I was you :)

Selecting Entity based on auto generated ID in google datastore

I have created an entity with few attributes but without specifying any key in which case an auto generated ID has been created in data-store.
Entity en=new Entity("Job");
Now when I fetch such entities and try to store it in Java object, how can I get the auto generated ID (which I required to perform UPDATE operation later)?
I have tried the below ways but it does not return Identifier value.
en.getProperty("__key__");
en.getProperty("ID/Name");
en.getProperty("Key");
You are probably looking for:
en.getProperty(Entity.KEY_RESERVED_PROPERTY)
mentioned in Key Filters (not an obvious place to find it).
Another approach would be to try:
en.getKey().getId()
mentioned in Entity JavaDoc and Key JavaDoc.

Is there any way to have key_name and id at the same time for GAE datastore entity?

In addition to the key_name I generate, I also would like to have some other property, which will act as id (I don't want to show key_name to the user). Can it be id? Or, how to generate unique value instead of id?
What I will do - I will generate a url with usage of that id and parent key name. If user clicks on this link, I'll need to find this datastore entity and update it.
Here is the current code.
Creation of the record:
item = Items.get_by_key_name(key_names=user_id, parent=person)
if item is None:
item = Items(key_name='id'+user_id, parent=person)
Getting the record:
item = Items.get_by_key_name(key_names=user_id, parent=person)
user_id is what should be hidden.
I could be probably wrong because your requirements are not clear, but for me you should pass just the key to the view using:
item.key()
then you could pass back the key to the controller and easily retrieve a given entity with:
item = Items.get(key)
Entities have exactly one of a key name or ID - never both. You could create an entity with a single ReferenceProperty pointing to your target entity, and use its ID as an identifier, but there really should be no reason not to reveal a key name to a user - a well authored app should not rely on this value remaining secret.
Note that it's trivially easy to extract the key name (and the rest of the information about a key) from the string encoded key.

Establishing entity groups while maintaining access to Long ids

I'm using the appengine datastore, and all of my entities have Long ids as their PrimaryKey. I use those ids to communicate with the client, since the full-fledged Keys take much more bandwidth to transmit.
Now, I want to form entity groups so that I can do complex operations within transactions, and it seems from http://code.google.com/appengine/docs/java/datastore/transactions.html#Entity_Groups that I need to use Keys or String encoded keys - the simple Longs are not an option.
I don't mind refactoring a little to use Keys, but I still want to avoid sending the behemoth things over the wire. How can I get a unique (per kind) Long identifier for an entity whose primary key is a Key?
You do not have to use names (strings). All of the KeyBuilder methods that take names also have counterparts that take ids (longs).
For transmission, you simply need the name or id part of a Key. Once you know the id or name, you can reconstruct the Key server side. If it is a child entity, you'll need to know both the parent and the child's names or ids.

Resources