Хорошая модель данных для поиска любимых историй пользователя - PullRequest
4 голосов
/ 13 октября 2009

Оригинальный дизайн

Вот как я изначально настроил Models:

class UserData(db.Model):
    user = db.UserProperty()
    favorites = db.ListProperty(db.Key) # list of story keys
    # ...

class Story(db.Model):
    title = db.StringProperty()
    # ...

На каждой странице, где отображалась история, я запрашивал данные пользователя для текущего пользователя:

user_data = UserData.all().filter('user =' users.get_current_user()).get()
story_is_favorited = (story in user_data.favorites)

Новый дизайн

После просмотра этого выступления: Google I / O 2009 - масштабируемые, сложные приложения на App Engine , я подумал, можно ли настроить их более эффективно,

class FavoriteIndex(db.Model):
    favorited_by = db.StringListProperty()

То же самое Story Model, но я избавился от UserData Model.Каждый экземпляр нового FavoriteIndex Model имеет экземпляр Story в качестве родителя.И каждый FavoriteIndex хранит список идентификаторов пользователей в своем свойстве favorited_by.

Если я хочу найти все истории, которые были добавлены определенным пользователем:

index_keys = FavoriteIndex.all(keys_only=True).filter('favorited_by =', users.get_current_user().user_id())
story_keys = [k.parent() for k in index_keys]
stories = db.get(story_keys)

Этот подход позволяет избежать сериализации / десериализации, которая иначе связана с ListProperty.

Эффективность против простоты

Я не уверен, насколько эффективен новый дизайн, особенно после того, как пользователь решит избрать 300истории, но вот почему мне это нравится:

  1. Избранная история связана с пользователем, а не с ним user data

  2. НаНа странице, где я отображаю story, довольно просто спросить story, была ли она добавлена ​​(без вызова отдельной сущности, заполненной пользовательскими данными).

    fav_index = FavoriteIndex.all().ancestor(story).get()
    fav_of_current_user = users.get_current_user().user_id() in fav_index.favorited_by
    
  3. Также легко получить список всех пользователей, которые одобрили историю (используя метод из # 2)

Есть ли более простой способ?

Пожалуйста, помогите,Как обычно это делается?

Ответы [ 4 ]

2 голосов
/ 14 октября 2009

То, что вы описали, является хорошим решением. Однако вы можете оптимизировать его дополнительно: для каждого избранного создайте сущность UserFavorite в качестве дочернего объекта соответствующей записи Story (или, что то же самое, в качестве дочернего объекта записи UserInfo), для имени ключа которого установлено уникальное значение пользователя. Я БЫ. Таким образом, вы можете определить, одобрил ли пользователь историю с помощью простого get:

UserFavorite.get_by_name(user_id, parent=a_story)

Операции get в 3-5 раз быстрее, чем запросы, так что это существенное улучшение.

1 голос
/ 19 октября 2009

С вашим новым дизайном вы можете искать, если пользователь добавил в избранное определенную историю с помощью запроса.
Вам не нужны объекты класса UserFavorite.
Это запрос keys_only, поэтому он не такой быстрый, как get (key), но быстрее, чем обычный запрос.
Все классы FavoriteIndex имеют одинаковое имя-ключа = 'favs'.
Вы можете фильтровать на основе __key__.

a_story = ......
a_user_id  = users.get_current_user().user_id()
favIndexKey = db.Key.from_path('Story', a_story.key.id_or_name(), 'FavoriteIndex', 'favs')
doesFavStory = FavoriteIndex.all(keys_only=True).filter('__key__ =', favIndexKey).filter('favorited_by =', a_user_id).get()

Если вы используете несколько FavoriteIndex как потомков истории, вы можете использовать фильтр предков

doesFavStory = FavoriteIndex.all(keys_only=True).ancestor(a_story).filter('favorited_by =', a_user_id).get()
1 голос
/ 14 октября 2009

Вы можете сделать любимый индекс как объединение двух моделей

class FavoriteIndex(db.Model):
    user = db.UserProperty()
    story = db.ReferenceProperty()

или

class FavoriteIndex(db.Model):
    user = db.UserProperty()
    story = db.StringListProperty()

Затем ваш запрос пользователя возвращает один объект FavoriteIndex для каждой истории, выбранной пользователем.

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

Вы не хотите сканировать что-либо, если не знаете, что оно ограничено небольшим размером

1 голос
/ 13 октября 2009

Я не хочу заниматься вашим актуальным вопросом, но вот очень маленький совет: вы можете заменить этот код:

if story in user_data.favorites:
    story_is_favorited = True
else:
    story_is_favorited = False

с этой единственной строкой:

story_is_favorited = (story in user_data.favorites)

Вам даже не нужно ставить скобки вокруг story in user_data.favorites, если вы этого не хотите; Я просто думаю, что это более читабельно.

...