ios - el patrón ''retweet'' de parse.com es demasiado detallado
swift design-patterns (1)
@jesses.co.tt Lo siento si esto es demasiado tarde, definitivamente tomo nota de que estoy respondiendo este mes después de que me lo pidieron, pero creo que esto vale la pena responder en general (y tal vez todavía podría ser de valor para ti).
En general, estoy 100% de acuerdo en que esa triple consulta con Parse es a) enormemente ineficaz como se factura (en el sistema anterior) yb) con eso en mente, parece ser el enfoque equivocado incluso con Parse autohospedado (que contextualmente es el único mecanismo utilizable en este punto desde que Parse se ha cerrado, pero creo que todavía habría estado activo posiblemente cuando se formuló la pregunta ... sin importar ...). Hay dos soluciones que veo que pueden solucionar esto de una manera bastante limpia, suponiendo que estos cambios se pueden hacer en el esquema general / arquitectura.
1) Una primera solución es volver a esquematizar el conjunto de datos y esencialmente "clave externa" el subconjunto de partidarios que cada User
tiene en la tabla de User
. De esta forma, en lugar de ir de Cause
-> Supporter
-> User
, en teoría, podrías hacer Cause
-> User
(donde los usuarios obtendrían sus seguidores de forma predeterminada ya que sería una columna allí). Para hacer esto en Parse
, si recuerdo correctamente puede configurar una columna para tener una matriz de cierto tipo como valor y luego tener enlaces de object
allí (que se muestran muy bien en el panel de Parse) que son objetos reales de la tabla Supporter
, pero manteniendo esta columna de enlaces a esa tabla en su tabla de User
.
Aunque hay un poco más de trabajo en el campo de la write
, ya que tendrás que hacerlo manualmente (es decir, escribir el código manualmente para hacerlo, debe ser automático, pero no será gratis en términos de desarrollo) . Con esta operación de write
poco más inicial, tendrá una read
2 pasos en lugar de 3.
2) Una segunda solución es usar un proveedor diferente para este tipo de datos, si la velocidad de consulta es un problema. En varios de mis proyectos utilizo enfoques basados en socket para este tipo de búsqueda de consulta de datos, y pienso como Pusher o Firebase (ambos niveles muy diferentes de "todo incluido", Firebase es mucho más parecido a un Parse pero de Google esta vez, siendo Pusher un poco más básico y "DIY").
Con Firebase , por ejemplo, y un socket para este conjunto de datos + un esquema en el que la tabla Cause
tiene un caché de lo que los User
pertenecen (y en qué User
tiene un caché de sus Supporter
), este aspecto de 3 pasos hasta podría ser efectivamente 1 consulta con 2 parámetros (que creo que es el escenario ideal). Creo que esto también se puede lograr con Parse, pero requeriría otro paso de refactorización de esquemas para la primera solución propuesta.
Creo que en los comentarios se recomienda algo similar a esto (ambas soluciones anteriores) pero en un formato mucho más no elaborado. Espero que esto ayude al preguntador original o a alguien. Esto podría también, teóricamente, como alguien recomendado, utilizar PubNub como se PubNub en 1 comentario, pero podría fácilmente construir este esquema en una base de datos PostgreSQL alojada en AWS o Heroku y lograr exactamente los mismos mecanismos que Parse sin la sobrecarga.
Además, dado que esto se refiere a Parse, que ahora solo se ofrece como una solución alojada de código abierto, aquí hay una guía para migrar al hosting de Parse por su cuenta en AWS: enlace aquí
Por lo tanto, se me ha encomendado la tarea de implementar una funcionalidad tipo ''retweet'' en una aplicación ( iOS, Swift ), usando Parse .
Esto se ha preguntado antes here , pero eso es a) bastante alto nivel yb) Tengo la tarea a mano - no estoy pidiendo ayuda sobre las decisiones arquitectónicas, aunque si parece que obviamente me falta algo, estoy feliz de aceptar comentarios.
Mi aplicación tiene CAUSAS que son creadas por un USUARIO. También hay una tabla de SEGUIMIENTO con un usuario TO y un usuario FROM. Entonces, para comenzar, simplemente consulto la tabla CAUSAS, con la restricción de que el USUARIO que publicó debe coincidir con el ID de objeto de un usuario TO (donde el usuario actual es el usuario FROM) en la tabla SEGUIR. Más sucintamente:
let getFollowedUsersQuery = PFQuery(className: Constants.kParseClassFollowers)
getFollowedUsersQuery.whereKey(Constants.kParseFieldFromUser, equalTo: PFUser.currentUser()!)
let causesQuery = PFQuery(className: Constants.kParseClassCauses)
causesQuery.whereKey(Constants.kParseFieldFromUser, matchesKey: Constants.kParseFieldToUser, inQuery: getFollowedUsersQuery)
causesQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let causes = objects {
for cause in causes {
// populate the tableview cells, etc.
}
}
})
Ahora tengo todas las causas de los usuarios que sigo ... eso es todo bastante estándar.
Aquí es donde se vuelve complicado.
Cada CAUSA también tiene una relación llamada PARTIDARIOS. Ahora necesito diseñar una manera de obtener todas las CAUSAS de personas que no sigo, pero que tienen en su lista de seguidores un usuario que yo sigo.
Todavía tengo que encontrar una solución elegante, aunque me estoy acercando a una de ''fuerza bruta'', y es tan engorrosa y prolija que la mejor mitad del cerebro de mi programador me grita como Susan Powter ...
Aquí hay una muestra:
let retweetQuery = PFQuery(className: Constants.kParseClassCauses)
retweetQuery.orderByDescending(Constants.kParseFieldCreatedAt)
retweetQuery.whereKey(Constants.kParseFieldFromUser, notEqualTo: PFUser.currentUser()!)
retweetQuery.whereKey(Constants.kParseFieldFromUser, doesNotMatchKey: Constants.kParseFieldToUser, inQuery: getFollowedUsersQuery)
retweetQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let causes = objects {
for cause in causes {
let supporterRelations = cause.relationForKey(Constants.kParseClassSupporters)
let supporterQuery = supporterRelations.query()
supporterQuery.findObjectsInBackgroundWithBlock { (supporters, error) in
if(error == nil && supporters?.count > 0) {
for supporter in supporters! {
let user:PFUser = supporter as! PFUser
getFollowedUsersQuery.whereKey(Constants.kParseFieldToUser, equalTo: user)
getFollowedUsersQuery.whereKey(Constants.kParseFieldFromUser, equalTo: PFUser.currentUser()!)
getFollowedUsersQuery.findObjectsInBackgroundWithBlock({ (results, error) -> Void in
if(error == nil && results?.count > 0) {
for result in results! {
// do stuff
}
}
})
}
}
}
}
}
})
Ahora, esto es pura locura, e increíblemente derrochador (especialmente teniendo en cuenta cómo Parse calcula el nivel libre - Siento que esto realmente podría contribuir en gran medida a mi límite API si se lleva a la producción).
Después de haber hecho dos consultas, rehago una por completo, luego realizo otra consulta para cada causa en las Relaciones de APOYO, luego realizo otra consulta sobre cada usuario en esa Relación para ver si las sigo ... y una vez que tengo esa información, Necesito pasar por las causas soportadas por el Usuario (debido a la devolución asincrónica de las consultas de Parse, no creo que pueda volver a alcanzar los bucles padre) ... que aún no implementé, porque Estoy a punto de tirar la toalla, ¡ tiene que haber una mejor manera!
Espero que me pierda una estrategia aquí ...