Consulta compuesta para Parse.com usando la API REST

Un proyecto que he henetworkingado actualmente usa Parse para el backend. Estoy intentando migrar la forma en que se obtienen / publican los datos, desde el iOS SDK de Parse hasta el uso de la API REST de Parse (utilizando AFNetworking ).

Pude convertir un PFQuery simple como el siguiente para su equivalente REST:

PFQuery

 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.'999Z'"]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]]; NSString *createdAt = [dateFormatter stringFromDate:createdAtDate]; PFQuery *query = [PFQuery queryWithClassName:@"Photo"]; [query whereKey:@"createdAt" lessThan:createdAt]; [query orderByDescending:@"createdAt"]; [query setLimit:10]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (!error) { //Etc... } }]; 

Solicitud API REST :

 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.'999Z'"]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]]; NSString *createdAt = [dateFormatter stringFromDate:createdAtDate]; NSString *dateQueryString = [NSString stringWithFormat:@"{\"createdAt\":{\"$lte\":{\"__type\":\"Date\",\"iso\":\"%@\"}}}", createdAt]; NSDictionary* parameters = @{@"order": @"-createdAt", @"limit": @10, @"include": @"user", @"where":dateQueryString}; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.requestSerializer = [AFJSONRequestSerializer parseSerializer]; // Already has App-Id, App-key and Content-Type set. NSMutableURLRequest* request = [manager.requestSerializer requestWithMethod:@"GET" URLString:@"https://api.parse.com/1/classes/Photo" parameters:parameters error:nil]; AFHTTPRequestOperation* operation = [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) { // Etc.. } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"%@", error.localizedDescription); }]; [operation start]; 

Sin embargo, el problema es con consultas compuestas como la siguiente:

 NSMutableArray* subqueriesArray = [NSMutableArray array]; PFQuery *followingActivitiesQuery = [PFQuery queryWithClassName:@"Activity"]; [followingActivitiesQuery whereKey:@“type” equalTo:@“Follow”]; [followingActivitiesQuery whereKey:@“fromUser” equalTo:[PFUser currentUser]]; followingActivitiesQuery.limit = 1000; PFQuery *privateUserQuery = [PFUser query]; [privateUserQuery whereKey:@“yourMomLikedThisPhoto” equalTo:[NSNumber numberWithBool:NO]]; // fake whereKey of course PFQuery *photosFromFollowedUsersQuery = [PFQuery queryWithClassName:@"Photo"]; [photosFromFollowedUsersQuery whereKey:@“yourMomLikedThisPhoto” equalTo:[NSNumber numberWithBool:YES]]; [photosFromFollowedUsersQuery whereKey:@“user” matchesKey:@“toUser” inQuery:followingActivitiesQuery]; [photosFromFollowedUsersQuery whereKey:@“user” matchesQuery:privateUserQuery]; PFQuery *photosFromCurrentUserQuery = [PFQuery queryWithClassName:@"Photo"]; [photosFromCurrentUserQuery whereKey:@“yourMomLikedThisPhoto” equalTo:[NSNumber numberWithBool:YES]]; [photosFromCurrentUserQuery whereKey:@“user” equalTo:[PFUser currentUser]]; [subqueriesArray addObject:photosFromFollowedUsersQuery]; [subqueriesArray addObject:photosFromCurrentUserQuery]; PFQuery *query = [PFQuery orQueryWithSubqueries:subqueriesArray]; [query includeKey:@"Photo"]; [query orderByDescending:@"createdAt"]; 

Si alguien me pudiera ayudar a entender cómo build los parameters para esto, realmente lo agradecería. Una idea general sobre cómo proceder en la dirección correcta también ayudará. Me he referido a la Guía API de Parse REST , pero parece que no puedo getla. Estoy tratando de hacerlo bien usando $inQuery , pero aún no $inQuery suerte.

Una respuesta a esta pregunta cubrirá la mayoría de los problemas comunes y complejos que uno enfrenta al consultar con la API Parse REST (en iOS).

Uso transformativo de $ o

Creo que lo que querrás hacer es transformar la siguiente llamada en una llamada http relevante usando la biblioteca que elijas (AFNetworking). Como puede ver, el comportamiento de la subconsulta se incrusta en una url codificada específica que contiene una matriz con dictionary cuyos valores son dictionarys con declaraciones de comparación.

 curl -X GET \ -H "X-Parse-Application-Id: ${APPLICATION_ID}" \ -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \ -G \ --data-urlencode 'where={"$or":[{"wins":{"$gt":150}},{"wins":{"$lt":5}}]}' \ https://api.parse.com/1/classes/Player 

( fuente )

Otro enfoque sería el uso de consultas de subclass.

Consultas de subclass

Puede get una consulta para los objects de una subclass en particular utilizando la consulta de método de class. El siguiente ejemplo de consultas para armaduras que el usuario puede permitirse:

 PFQuery *query = [Armor query]; [query whereKey:@"rupees" lessThanOrEqualTo:[PFUser currentUser][@"rupees"]]; [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) { if (!error) { Armor *firstArmor = [objects firstObject]; // ... } }]; 

( fuente )

Consultas relacionales

Existen varias forms de emitir consultas para datos relacionales. Si desea recuperar objects donde un campo coincide con un object PFO particular, puede usar whereKey: equalTo: al igual que para otros types de datos. Por ejemplo, si cada comentario tiene un object Publicar en su campo de publicación, puede get comentarios para un Mensaje en particular:

 // Assume PFObject *myPost was previously created. // Using PFQuery PFQuery *query = [PFQuery queryWithClassName:@"Comment"]; [query whereKey:@"post" equalTo:myPost]; [query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) { // comments now contains the comments for myPost }]; // Using NSPnetworkingicate NSPnetworkingicate *pnetworkingicate = [NSPnetworkingicate pnetworkingicateWithFormat:@"post = %@", myPost]; PFQuery *query = [PFQuery queryWithClassName:@"Comment" pnetworkingicate:pnetworkingicate]; [query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) { // comments now contains the comments for myPost }]; 

One Parse Blog Post también menciona que los pnetworkingicados se pueden mejorar aún más usando:

En este momento, admitimos estas características de NSPnetworkingicate:

Comparaciones simples como =,! =, <,>, <=,> =, Y ENTRE con una key y una constante. Los pnetworkingicados de contención, como x IN {1, 2, 3}. Los pnetworkingicados de la existencia key, como x EN EL SI MISMO. COMIENZA CON expresiones. Compuesto pnetworkingicados con AND, OR y NOT. Subconsultas con "key IN% @", subconsulta. Consulte nuestros documentos para get más detalles y ejemplos.

Consejos específicos sobre la descomposition de parameters

Sugiero evaluar cualquier muestra que muestre cómo se interpretan los valores de la API REST. Teniendo en count que la mayoría de las transmisiones probablemente representarán un formatting similar a JSON. En estos casos '[' los apoyos cuadrados son matrices, '{' los apoyos rizados representan dictionarys y querrás codificar los datos parametrizados antes de presionarlo en tu request http.

Información aplicada

Tomando lo que se menciona anteriormente, puede crear una llamada a la API REST. Debe codificar la cláusula where de los diversos criterios específicos de su caso de uso. El siguiente método se puede usar para garantizar que esos parameters estén en línea con las properties de consulta que necesita:

 var encodedParam = param.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) 

Suponiendo que el parámetro anterior es una cadena con sus valores-key similar a:

 'where={"$or":[{"wins":{"$gt":150}},{"wins":{"$lt":5}}]}' 

Los parameters codificados se agregarán después de su identificación de la aplicación y la key de la API REST en la cadena de consulta básica REST-API, esto debería devolver los objects que desee: api-query (observe la cuarta url utilizada para las consultas).

Parece que los parameters codificados deberían ir después del nombre de class al que se hace reference anteriormente, como en el siguiente ejemplo:

codificados-params (extrapola tus valores usando el formatting anterior, también nota los caracteres adicionales en la cadena de consulta "… classname ?% s codedParams").

Otros operadores de consulta que puede usar incluyen:

operadores de consulta

Ejemplos de consulta adicionales

otro ejemplo

Se podría extrapolar cómo build consultas más complejas utilizando los ejemplos suministrados en el website de Parse. Embalar estas consultas en parameters codificados debería producir los resultados que busca. Lo que haría sería primero build una consulta utilizando la API Parse normal y luego convertirla a la construcción REST-API identificada anteriormente.

P.ej:

 let urlpath = NSString(format: "https://api.parse.com/1/classes/Photo?%s\(encodedParams)") ... add code to call the urlPath 

Respuesta específica a su problema principal

Después de volver a leer la pregunta, quería responder a su problema específico con la necesidad de agregar varias subconsultas en la list de parameters de la API REST. Creo que una inspección cercana de la cláusula $ o sería útil. Siempre que pueda aplicar keys relacionadas en el object Foto en el criterio múltiple, entonces debería ser capaz de lograr su objective.

 'where={"$or":[{"wins":{"$gt":150}},{"wins":{"$lt":5}}]}' 

Ejemplo de consulta compuesta

La cláusula $ o es el ejemplo utilizado en el website de Parse en consultas compuestas. El código anterior se puede transportar a su caso de uso y se aplica mediante el método url codificado especificado anteriormente.

compound-query

Nota Bene

Tenga en count que el siguiente ejemplo muestra la recuperación de varios objects relacionados (usando $ inQuery). Hay límites con respecto a cuántos objects internos se pueden recuperar. Noté que básicamente es la equivalencia de lo que estás haciendo en el código, así que es de esperar que la extrapolación sea relativamente sencilla usando esta muestra.

objetos múltiples

Precaución

Tenga en count esta advertencia de Parse sobre cuándo usar la REST-API.

descanso-api-precaución