New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datastore Key is not returned on runQuery with new entity change #1768

Closed
grandmore opened this Issue Nov 3, 2016 · 7 comments

Comments

Projects
None yet
6 participants
@grandmore

grandmore commented Nov 3, 2016

With the new change to Datastore where runQuery returns entities instead of the old nested json object, there seems to be no way to retrieve the key along with the entity.

I'm currently returning a list of 40 entities at a time with no way to save the ID's with the entities. I'm mapping into a GraphQL server where the ID's are used as part of the cursors.

The documentation has no information on this. Is there an option or am I missing something?

Thanks

@stephenplusplus

This comment has been minimized.

Member

stephenplusplus commented Nov 3, 2016

Sorry about that. It looks like we haven't done a release since we updated the docs. We left behind many examples that were invalidated when we switched from the nested object.

The way to get the key is by using a special property (a Symbol we provide):

var key = entity[datastore.KEY]

Sorry for the confusion, we should have a new release out soon so the docs can be refreshed.

related: #1719, #1724, #1730

@richardkazuomiller

This comment has been minimized.

richardkazuomiller commented Nov 17, 2016

Can I ask what the benefit of changing entity.key to entity[datastore.KEY] is? It seems pretty unconventional to me and it breaks a lot of my code.

@puppetmaster3

This comment has been minimized.

puppetmaster3 commented Feb 28, 2017

Does not work, I tried the new way, and you can't get the key back via query.

@mrkevinze

This comment has been minimized.

mrkevinze commented May 8, 2017

The key is undefined for me when I used entity[datastore.KEY].

I am using "@google-cloud/datastore": "1.0.0".

// Batch get
datastore.get(userKeys).then((userEntities) => {
  var entity = userEntities[0];
  var key = entity[datastore.KEY]; // undefined
});

Update (there's no problem)
It turns out that there was an outer array that I had to access first. Examples in the docs also showed that you had to access element zero; I was tripped up because I was doing a batch get. I do wonder why there's a need for the outer array though.

datastore.get(userKeys).then((result) => {
  var entities = result[0];
  var firstEntity = entities[0];
  var firstEntityKey = firstEntity[datastore.KEY];
});

To illustrate:
If you pass in one key to get, the result is [entity] (if the entity exists).
If you pass in an array of keys to get, e.g. [key1, key2], the result is [ [entity1, entity2] ]

@stephenplusplus

This comment has been minimized.

Member

stephenplusplus commented May 8, 2017

Thanks for writing that up. Here are all the ways to use get() and the results they give:

// Callback with a single key
datastore.get(key1, function(err, entity) {
  // entity = { key1's data object }
})

// Callback with multiple keys
datastore.get([key1, key2], function(err, entities) {
  // entities = [
  //   { key1's data object },
  //   { key2's data object }
  // ]
})

// Promise with a single key
datastore.get(key1)
  .then(function(data) {
    var entity = data[0]
    // entity = { key1's data object }
  })

// Promise with multiple keys
datastore.get([key1, key2])
  .then(function(data) {
    var entities = data[0]
    // entities = [
    //   { key1's data object },
    //   { key2's data object }
    // ]
  })

The history

Before we supported callbacks, we wanted get to "make sense". So if you were only looking one thing up, you wouldn't get a pointless array back. We just wanted to give the thing you wanted.

Our callbacks have a consistent signature, where possible:

method(function (err, thingOrThingsYouWanted, apiResponse) {})

Because of that third argument, apiResponse, we had two choices for the signature for promises:

method()
  .then(function(data) {
    // an array:
    data = [ thingOrThingsYouWanted, apiResponse ]

    // an object:
    data = {
      thingOrThingsYouWanted: thingOrThingsYouWanted,
      apiResponse: apiResponse
    }
  })

The array was decided to be the best option. Because of that, datastore.get([key1, key2]) in promise mode ends up with an array inside an array. I'm not sure that we should remove that behavior, because it would be inconsistent from the rest of our API. (See #2167)

@mrkevinze

This comment has been minimized.

mrkevinze commented May 8, 2017

Stephen, many thanks for the detailed explanation and sharing about the history. Now I understand why there is an array inside an array for the promise call. I'll comment on #2167.

@getDanArias

This comment has been minimized.

getDanArias commented Aug 30, 2017

@mrkevinze You saved my life! I don't even remember how I got to this result, but I am glad I did! I am still trying to understand the mechanics of Google Datastore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment