问题
I need to assign a unique identifier to each entity in datastore. I've found AllocateIDs but the issue is that it generates integers and I use strings for the keys. Is it safe to convert the integer to a string or there is a risk of collision (i.e. datastore to return me the same integer that I'm currently using as a string key). ?
回答1:
Let's clear some things first:
The identifier part of an entity's key can either be
- a key name string
- or an integer numeric ID
But not both. So when you save an entity, its key either has a string
id called name OR (exclusive OR) an int64
id called intID.
The 2 optional identifier fields are distinct: if you have an entity with name="1234"
it is different from that of with intID=1234
.
When you save a new entity without explicitly specifying a name
or intID
, the datastore will assign a new unique intID
identifier to it. The datastore will never assign a string
name
by itself. You can only have entities with string
name
identifiers if you specify a string
name
yourself.
The datastore knows about the automatically generated intID
s it generates itself, and will never generate the same intID
twice (well behavior). However when saving a new entity if you specify an intID
yourself, you have to take care about it being unique. This would require to first check if the intID
you whish to use is not yet in use (e.g. by querying it first to see if no entity has that intID
yet) but even this would not be 100% guarantee that by the time you end up actually saving an entity with this will still be unused. The AllocateIDs() function can be used to obtain a continuous range of intID
s which the datastore will not use to generate intID
s by itself later on, so you are free to use the allocated range of intID
s safely. This also means that if there are concurrent requests also trying to save new entities (either in the same instance or in other instances), they will also never end up using these intID
s if identifier generation is left to the datastore.
Back to you question
Do you really need manual identifier assignment? In most of the cases this is only used/required if you already have a unique property of the entity which cannot be the same for 2 different entities (for example entity is Person
which has a property IdentityCardId
which is already unique to each person).
If you have such a unique property, you may use that which itself by nature ensures uniqueness. If you have no such property, then you should not use manual identifier assignment in the first place, you can just use/rely on automatic intID
assignment of the datastore.
Note that you can have mixed identifiers of different entities of the same kind (e.g. you can have a Person
with intID
and another Person
with name
).
As noted above, intID
s and name
s are distinct. So AllocateIDs()
does not take entities with name
identifiers into account just because the name
contains a valid number. From the datastore you don't get help to "allocate" a name
identifier (analog to the AllocateIDs()
to allocate intID
s), so it must be application logic to ensure the assigned name
is unique else you will end up "overwriting"/replacing an existing entity.
回答2:
You can avoid any possibility of a collision by prefixing an id with any string that you know you never use for your keys. For example:
String key = "id" + entity.getKey().getId();
And all of this is necessary only if you ever use a sequence of integers for your string keys.
回答3:
The way to get the datastore to generate string keys for you is to use NewIncompleteKey.
ikey := datastore.NewIncompleteKey(ctx, "Thing", nil)
key, _ := datastore.Put(ctx, ikey, nil) // TODO: check the error
fmt.Println(key.Encode()) // randomly-generated string key
Then to get it back from the string key...
ks := req.FormValue("key") // e.g., from an HTTP request parameter
key, _ := datastore.DecodeKey(ks) // TODO: check the error
var t Thing
_ = datastore.Get(ctx, key, &t) // TODO: check the error
来源:https://stackoverflow.com/questions/29567819/can-i-use-allocateids-as-string-datastore