2011-02-10 11 views
5

En mi aplicación, los usuarios pueden seguir a otros usuarios y recibir actualizaciones cada vez que las personas que siguen realizan una actividad.Seguir la estructura del modelo del almacén de datos en App Engine - Ordenar seguidores por fecha

almaceno las relaciones seguimiento de esta manera:

class User(db.Model): 
    ''' User details ''' 
    username = db.StringProperty() 

class Contacts(db.Model): 
    '''Store users contacts 
     parent= User (follower) 
     key_name= Users username (follower) 
     contacts = A list of keys of Users that a User follows ''' 
    contacts = db.ListProperty(db.Key) 
    last_updated = db.DateTimeProperty(auto_now=True) 

seguidores conseguir, y Usuarios que un usuario sigue (seguidores & siguientes):

'''Get Users that my_user follows''' 
my_user = User().all().fetch(1) 
contacts = Contacts.get_by_key_name(my_user.username).contacts 

''' get my_user followers - copied from an answer here on stackoverflow ''' 
follower_index = models.Contacts.all(keys_only=True).filter('contacts =',my_user) 
follower_keys = [f.parent() for f in follower_index] 
followers = db.get(follower_keys) 

Por lo tanto, quiero pedir my_user seguidores por fecha de seguimiento (que no sigo en los modelos anteriores), pero no estoy seguro de cuál es la mejor manera de hacerlo. Estas son las opciones que se me ocurren:

1) en lugar de la estructura actual de los contactos (db.Model), utilizar un modelo de "puente":

class Contacts(db.Model): 
    follower = db.ReferenceProperty(User) 
    following = db.ReferenceProperty(User) 
    date_created = db.DateTimeProperty(auto_now_add=True) 

Sin embargo, todavía tengo que averiguar cómo asegurarme de que tengo entidades únicas follower-> following: follower = user1, following = user2 no debería repetir. Puedo hacer eso si aplico 2 filtros a mi consulta, creo.

2) Mantener la estructura del modelo actual, pero en lugar de tener una lista de claves en Contactos (db.Model), almacenar una tupla: [user_key, date_created] de la siguiente manera:

class Contacts(db.Model): 
     '''Store users contacts 
      parent= User (follower) 
      key_name= Users username (follower) 
      contacts = A list of Tuples: User.key(), date_created ''' 
     contacts = db.StringListProperty() 
     last_updated = db.DateTimeProperty(auto_now=True) 

Sin embargo, esta manera voy a tener que procesar la lista de contactos: - tengo que extraer las claves de usuario y DATE_CREATED de cada cadena en el StringList() - Entonces puedo ordenar la lista de claves de usuario por fecha de creación

3) Última solución (claramente no eficiente): mantener la estructura de base de datos original y almacenar la actividad de seguimiento del usuario en un Modo separado l - cada acción de seguimiento se almacena por separado con un campo date_created. Use esta tabla solo para poder ordenar la lista de seguidores de los usuarios por fecha. Por supuesto, esto significa que voy a hacer dos pone almacén de datos - uno de Contactos() y otro a FollowNewsFeed() de la siguiente manera:

Class FollowNewsFeed(db.Model): 
    ''' parent = a User follower''' 
    following = db.ReferenceProperty(User) 
    date_created = db.DateTimeProperty(auto_add_now=True) 

Cualquier ideas sobre la mejor manera de lidiar con esto son muy apreciados :)

¡Gracias!

Respuesta

3

me gustaría utilizar un modelo para mapear desde el usuario a su destino en lugar de una lista:

  1. Inserción de una nueva instancia o eliminación de uno ya existente, probablemente será más rápido que la modificación de una lista enorme y vuelva a guardarla . Además, a medida que crece el tamaño de followed, puede consultar un subconjunto de la lista en lugar de buscarlo todo (consulte a continuación por qué).

  2. Obtiene espacio de atributo adicional y no tiene que preocuparse tanto por la necesidad de rediseñar y mezclar con listas en el futuro.

  3. No tiene que preocuparse por los límites de índice con las listas (each item takes up a slot, up to 5000).

desgracia es probable que golpear another limit much sooner:

A single query containing != or IN operators is limited to 30 sub-queries. 

Lo que significa que cada elemento va a consumir una ranura [ej. in (1,2,3) = 3 ranuras]. Por lo tanto, incluso en una cantidad relativamente pequeña (~ 30 seguidores) necesitará hacer múltiples viajes a la base de datos y anexar resultados.

Suponiendo que la gente no quiere volverse loca en su página, tarda cientos de años en cargar y el tiempo que necesitará algún tipo de límite sobre la cantidad de personas que pueden seguir. Si se siguen 100 personas, se necesitarán unos buenos 4 a 5 viajes y habrá que ordenar los datos en su aplicación o en el lado del cliente mediante javascript.

+0

Gracias! Interesante: no he pensado en el límite de las consultas secundarias. Ese es otro problema del que tendré que ocuparme, especialmente que como mencionaste, necesito ordenar el conjunto de resultados por fecha, así que necesito tenerlo todo en una lista antes de mostrarlo al usuario. – yasser

+0

Personalmente Yo usaría ajax para buscar los datos. Divídalo en viajes de 20 contactos con actualizaciones de los últimos 7 días o 100 en total, o algo así, luego ordene y muestre los resultados a través de javascript. Solo asegúrate de no utilizar ajax para la lista del perfil/mensaje de las personas para que google pueda indexarlo si así lo deseas. – Matt

+0

que significa: (1) obtener la lista de contactos de usuario (2) obtener la lista de actualizaciones de estos contactos dividiendo la lista en listas de 20 contactos (3) obtener actualizaciones de estos contactos, filtrando por nombre de contacto y fecha_creada (último 7 días) (4) si lista de resultados <10, obtenga resultados de los siguientes 20 contactos y añádalos a la lista de actualizaciones (5) si la lista todavía tiene <10 actualizaciones, comience nuevamente y amplíe el intervalo de fechas (obtenga actualizaciones para el pasado 14 días en su lugar) .. En lugar de este lío, tal vez debería almacenar todas las actualizaciones en una bandeja de entrada de usuario para evitar sub-quries ... lo que significa que voy a hacer muchas escrituras: -/ – yasser

Cuestiones relacionadas