Arjen
Arjen

Reputation: 5313

Google Datastore entity key id is a string instead of number

When I save an entity to the datastore with a numeric key:

datastore.save({
  key: datastore.key(['Thing', 123]),
  data: [
    { name: 'name', value: 'My thing' }
  ]
});

And then retrieve it again

datastore
  .createQuery('Thing')
  .filter('__key__', datastore.key(['Thing', 123]))
  .select('__key__')
  .run((err, entities) => {
    const key = entities[0][datastore.KEY];
    console.log(`key.id = ${key.id}, type = ${typeof key.id}`);
  });

This outputs:

 key.id = 123, type = string

But I'd expect it to output:

 key.id = 123, type = number

The datastore library seems to go through great lengths to ensure that the ID is a number, but then proceeds to return it as as string. When using the ID to create a new key, e.g.

const newKey = datastore.key(['Thing', key.id]);

This returns a key that will be unable to find any entities, because the value will be assigned to the name instead of the id because it's a string.

I've made a small repro case here: https://github.com/arjenvanderende/datastore-key-id-is-string

It seems very strange to me that the ID is returned as a string instead of a number. Is this expected behaviour or is this a bug in the library?

edit

This issue becomes a bigger problem when you have a "foreign key" to another object and you use key.id to set it. E.g.

datastore.save({
  key: datastore.key(['Thing', 234]),
  data: [
    { name: 'name', value: 'My other thing' }
    { name: 'parentThingId', value: thing[datastore.KEY].id }
  ]
});

After retrieving this object again from the datastore, looking up the parent of the other thing will fail. Doing a lookup in the datastore with the key datastore.key(['Thing', otherThing.parentThingId) will yield no results, because it tries to lookup it up by name instead of id. It isn't immediately apparent that this is the issue, because types are somewhat hidden in the datastore console.

Upvotes: 1

Views: 2644

Answers (1)

Stephen
Stephen

Reputation: 5770

It is a string, but it is recognized as an id. The API does the proper thing when you make future requests with the key object.

We have to do some special-case handling in the library, because IDs can be very long-- beyond the allowable ceiling for a JavaScript integer. Our storing it as a string is an internal artifact that should not affect the user.

When using the ID to create a new key, e.g.

const newKey = datastore.key(['Thing', key.id]);

Why not just use key itself instead of creating a new Key object?

Alternatively, you can force the ID type by using:

const newKey = datastore.key(['Thing', datastore.int(key.id)]);

Upvotes: 4

Related Questions