Как найти объекты, где ключ НЕ находится в StringListProperty в GoogleAppEngine - PullRequest
3 голосов
/ 14 августа 2011

Я почти уверен, что вышесказанное НЕ возможно напрямую (но я был бы рад ошибаться). Вот что я пытаюсь сделать, но я не могу понять, как заставить полезный запрос работать.

class Challenge(db.Model):
    name = db.StringProperty()
    players = db.StringListProperty(default=[])
    created_on = db.DateTimeProperty(auto_now_add=True)
    completed_on = db.DateTimeProperty(default=None)

Там могут быть тысячи проблем. Вы можете присоединиться к любому количеству испытаний в любое время (до его завершения), но вы можете присоединиться к любому вызову только один раз.

edit -----------------------------

Вызовы выполняются асинхронно (они могут длиться несколько дней), и в конце этого периода определяется «победитель», поэтому люди могут столкнуться с несколькими вызовами одновременно, ожидая их завершения. По сути, вы присоединяетесь к испытанию и завершаете задание, затем ждете, пока другие сделают то же самое, затем победитель выбирается, когда испытание заканчивается. Пока вы ждете, вы можете присоединиться и выполнить другие задачи. Существует ограничение 250-500 человек на вызов (еще не определился с максимальным)

------------------------------ редактировать

Я хочу составить список всех испытаний, к которым вы МОЖЕТЕ присоединиться, упорядоченных по created_on. players - это список str(user.key()) для всех тех, кто присоединился к вызову.

Вы можете сделать что-то вроде:

already_in = Challenge.all().filter('players = ', str(self.user.key())).filter('completed_on =', None)
already_in_set = set()    
for challenge in already_in.fetch(1000):
    already_in_set.add(str(challenge.key()))  # Could cache this in the user object

challenges = Challenge.all().order('created_on')
keepers = []
for challenge in challenges:
    if str(challenge.key()) not in already_in_set:
        keepers.append(challenge)
        if len(keepers) > 11:
            break

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

Конечно, есть другой способ сделать это. (Я тоже не против реструктуризации БД, чтобы она работала лучше)

Я мог бы кешировать уже_in_set как StringListPropery(indexed=False) на объекте User, и это обеспечило бы некоторое ускорение, но тогда мне пришлось бы сократить это, чтобы удалить вызовы, которые сейчас выполнены (что я мог сделать за пределами Запрос пользовательского интерфейса).

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

Ответы [ 2 ]

3 голосов
/ 14 августа 2011

Как вы уже догадались, это на самом деле невозможно. Элементы в свойствах списка индексируются индивидуально, поэтому фильтр «не равно x» вернет любой список, который имеет хотя бы одно значение, не равное x, а не желаемый результат.

Однако, учитывая ситуацию, которую вы описываете, маловероятно, что пользователи столкнутся с неограниченным количеством проблем. Выбор проблем, с которыми они уже сталкиваются, и фильтрация этих результатов по наборам результатов, кажется разумным решением. Если вы хотите сделать вещи более эффективными, вы можете хранить список вызовов для пользователя, а не наоборот. Это также означает, что больше не существует практического ограничения на количество пользователей, которые могут принять участие в задании.

Наконец, не используйте db.StringListProperty для хранения сериализованных ключей - вместо этого используйте db.ListProperty(db.Key).

0 голосов
/ 14 августа 2011

Учитывая ограничение на то, что пользователь может присоединиться только к одному вызову за раз, если вы записываете незавершенный запрос (если таковой имеется), в котором участвует пользователь, вы можете извлечь его очень эффективно. Затем (если я вас правильно понимаю) применяется один из двух случаев: либо пользователь уже участвует в конкурсе, и в этом случае запрос в конкурсе не требуется, либо вам необходимо запросить доступные вызовы. Для выполнения последнего запроса может также помочь сохранить флаг completed в конкурсе.

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

...