Запрос хранилища данных google по ключу в gcloud api

Я пытаюсь запросить некоторые данные, используя gcloud API, который я только что обнаружил. Я хотел бы запросить KeyPropery. например.:

from google.appengine.ext import ndb

class User(ndb.Model):
    email = ndb.StringProperty()

class Data(ndb.Model):
    user = ndb.KeyProperty('User')
    data = ndb.JsonProperty()

В GAE я могу довольно легко запросить это, если у меня есть ключ пользователя:

user = User.query(User.email == '[email protected]').get()
data_records = Data.query(Data.user == user.key).fetch()

Я хотел бы сделать что-то подобное, используя gcloud:

from gcloud import datastore

client = datastore.Client(project='my-project-id')
user_qry = client.query(kind='User')
user_qry.add_filter('email', '=', '[email protected]')
users = list(user_qry.fetch())
user = users[0]

data_qry = client.query(kind='Data')
data_qry.add_filter('user', '=', user.key)  # This doesn't work ...
results = list(data_qry.fetch())  # results = []

Глядя на документацию для add_filter, не видно, что Entity.key является поддерживаемый тип:

value (int, str, bool, float, NoneType, :classdatetime.datetime) — значение для фильтрации.

Можно ли добавить фильтры для ключевых свойств?


Я провел еще немного поисков, чтобы попытаться выяснить, что здесь происходит на самом деле. Я не уверен, что это полезно для меня, чтобы понять эту проблему в настоящее время, но, возможно, это будет полезно для кого-то еще.

Я смоделировал базовые вызовы в соответствующих библиотеках для записи буферов протокола, которые сериализуются и отправляются на сервер. Для GAE это Batch.create_async в datastore_query.

Для gcloud это datastore.Client.connection.run_query. метод. Глядя на получившиеся буферы протокола (анонимизированные), я вижу:

gcloud запрос pb.

kind {
  name: "Data"
}
filter {
  composite_filter {
    operator: AND
    filter {
      property_filter {
        property {
          name: "user"
        }
        operator: EQUAL
        value {
          key_value {
            partition_id {
              dataset_id: "s~app-id"
            }
            path_element {
              kind: "User"
              name: "user_string_id"
            }
          }
        }
      }
    }
  }
}

GAE-запрос pb.

kind: "Data"
Filter {
  op: 5
  property <
    name: "User"
    value <
      ReferenceValue {
        app: "s~app-id"
        PathElement {
          type: "User"
          name: "user_string_id"
        }
      }
    >
    multiple: false
  >
}

Насколько я могу судить, две библиотеки используют разные версии прототипа, но передаваемые данные выглядят очень похожими...


comment
Я добавил ответ. Если это в конечном итоге сработает для вас, было бы неплохо зарегистрировать проблему в проекте gcloud-python, чтобы исправить документацию (и, возможно, сообщение об ошибке, которое вы получили в исходном коде).   -  person Ed Davisson    schedule 17.03.2016
comment
@EdDavisson - Спасибо за ответ, но либо я неправильно понял ваш ответ, либо вы неправильно поняли мой вопрос :-). Я думаю, вы отвечаете на вопрос: как мне запросить таблицу X по ключу объекта X. Я спрашиваю, как мне запросить таблицу X по свойству, в котором хранится ключ из объекта вида Y.   -  person mgilson    schedule 17.03.2016
comment
Вы абсолютно правы - я отвечал на другой вопрос. Можете ли вы отправить электронное письмо на адрес, указанный в моем профиле? Было бы полезно увидеть исходные дампы прототипов, которые вы разместили выше.   -  person Ed Davisson    schedule 18.03.2016


Ответы (1)


Это небольшая ошибка при использовании библиотеки ndb:

Все свойства ndb принимают один позиционный аргумент, указывающий имя свойства в хранилище данных

Глядя на определение вашей модели, вы увидите user = ndb.KeyProperty('User'). На самом деле это не означает, что свойство user является ключом объекта User, но что оно должно храниться в хранилище данных с именем свойства User. Вы можете проверить это в своем запросе к буферу протокола gae, где имя свойства (с учетом регистра) User.

Если вы хотите ограничить ключ одним типом, вам нужно указать его с помощью параметра kind.

user = ndb.KeyProperty(kind="User") 

KeyProperty также поддерживает:

user = ndb.KeyProperty(User)   # User is a class here, not a string

Вот описание всей магии.

Как и сейчас, ваш запрос gcloud запрашивает неправильного пользователя и должен быть:

data_qry = client.query(kind='Data')
data_qry.add_filter('User', '=', user.key)
person Patrick Costello    schedule 18.03.2016
comment
Великолепно! Спасибо, ребята, за помощь! - person mgilson; 18.03.2016