2015-05-13 11 views
8

Un progetto che ho ereditato attualmente utilizza Parse per il backend. Sto provando a migrare il modo in cui i dati vengono recuperati/postati, dall'SDK iOS di Parse all'utilizzo dell'API REST Parse (utilizzando AFNetworking).Query composta per Parse.com utilizzando l'API REST

sono stato in grado di convertire un semplice PFQuery come la seguente al suo REST equivalente:

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... 
    } 
}]; 

API REST Richiesta:

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]; 

Il problema però è con composti que Ries come quello qui sotto:

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"]; 

Se qualcuno potesse aiutarmi a capire come costruire la parameters per questo, mi piacerebbe davvero apprezzare. Sarà d'aiuto anche un'idea generale su come procedere nella giusta direzione. Ho rinviato allo Parse REST API Guide, ma non riesco a ottenerlo. Sto cercando di farlo bene usando $inQuery, ma ancora senza fortuna.

Una risposta a questa domanda coprirà la maggior parte dei problemi comuni e complessi che si presentano quando si esegue una query con l'API REST Parse (su iOS).

+0

provare a eseguire l'applicazione con monitoraggio Carlo per vedere esattamente quello che manda – Wain

+0

È possibile ottenere tutti i record con query normale REST API e si può applicare vincoli da predicati. Questo può aiutarti a ottenere la soluzione. –

+0

@ AjayGabani, va bene, ma se volessi farlo, lo avrei fatto prima. Devo ottimizzare anche l'utilizzo dei dati. Cosa succede se ci sono un milione di record nel database, ma solo 20 che soddisfano la mia query composta? Non sarà una buona pratica. – n00bProgrammer

risposta

2

uso trasformativa di $ o

penso che ciò che si vuole fare è trasformare la seguente chiamata in una chiamata http rilevante utilizzando la libreria di vostra scelta (AFNetworking). Come puoi vedere, il comportamento delle subquery è incorporato in un url codificato specifico che contiene un array con un dizionario i cui valori sono dizionari con istruzioni di confronto.

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 

(source)

Un altro approccio sarebbe l'uso di query sottoclasse.

sottoclasse query

si può ottenere una query per gli oggetti di una particolare sottoclasse utilizzando la query metodo della classe. L'esempio seguente query per armature che l'utente può permettersi:

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

(source)

relazionali query

Ci sono diversi modi per eseguire query per i dati relazionali. Se vuoi recuperare oggetti in cui un campo corrisponde a un particolare PFObject, puoi usare whereKey: equalTo: proprio come per altri tipi di dati.Ad esempio, se ogni commento è un oggetto Share suo settore postale, è possibile recuperare i commenti per un particolare messaggio:

// 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 NSPredicate 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"post = %@", myPost]; 
PFQuery *query = [PFQuery queryWithClassName:@"Comment" predicate:predicate]; 

[query findObjectsInBackgroundWithBlock:^(NSArray *comments, NSError *error) { 
    // comments now contains the comments for myPost 
}]; 

Uno Parse Blog Post menziona anche che predicati possono essere ulteriormente migliorate utilizzando:

in questo momento, ci supportano queste caratteristiche NSPredicate:

paragoni semplici come =, =, <,>, < =,> =, e TRA con una chiave e una costante!. Prassi di contenimento, come x IN {1, 2, 3}. Prassi di esistenza chiave, come x IN SELF. INIZIA CON espressioni. predicati composti con AND, OR e NOT. Sottoquery con "chiave IN % @", sottoquery. Vedi i nostri documenti per maggiori dettagli ed esempi.

suggerimenti specifici in decomposizione Parametri

Io suggerirei di valutare i campioni che mostrano come i valori API REST sono interpretati. Tenendo presente che la maggior parte delle trasmissioni probabilmente rappresenterà un formato simile a JSON. In questi casi '[' le parentesi quadre sono array, '{' le parentesi graffe rappresentano i dizionari e ti consigliamo di codificare i dati parametrizzati prima di inserirlo nella tua richiesta http.

dell'informazione applicata

Facendo ciò che viene discusso in precedenza, è possibile creare una chiamata API REST. Devi codificare la clausola where dei vari criteri specifici per il tuo caso d'uso. Il seguente metodo può essere utilizzato per garantire i parametri sono in linea con le proprietà della query è necessario:

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

Supponendo che param di cui sopra è una stringa con i tuoi valori-chiave simili a:

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

Il i parametri codificati verranno aggiunti dopo l'ID dell'applicazione e la chiave dell'API REST sulla stringa di query REST-API di base - questo dovrebbe restituire gli oggetti desiderati: api-query (notare il quarto URL utilizzato per le query).

Sembra che i parametri codificati dovrebbe andare dopo il nome di classe di cui sopra, come nel seguente esempio:

encoded-params (estrapolare i valori utilizzando il formato di cui sopra, si noti anche i caratteri extra sulla stringa di query" ... classname ?% s encodedParams ").

Ulteriori operatori di query si consiglia di utilizzare sono:

query-operators

Esempi query aggiuntiva

another-example

Si potrebbe estrapolare come costruire query più complesse, utilizzando il examples fornito nel websit Parse e.Imballare queste query in parametri codificati dovrebbe produrre i risultati che cerchi. Quello che vorrei fare è prima costruire una query usando l'API Parse regolare e poi convertirla nel costrutto REST-API identificato sopra.

Esempio:

let urlpath = NSString(format: "https://api.parse.com/1/classes/Photo?%s\(encodedParams)") 

... add code to call the urlPath 

risposta specifica al tuo problema principale

dopo aver riletto la domanda che volevo rispondere al tuo problema specifico con la necessità di aggiungere più sottoquery sul resto -Elenco dei parametri API. Penso che sarebbe utile un'osservazione ravvicinata della clausola $ o. Finché è possibile applicare le chiavi relative all'oggetto Foto nel criterio multiplo, si dovrebbe essere in grado di raggiungere il proprio obiettivo.

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

Compound Query Esempio

Il $ o clausola è l'esempio utilizzato sulla Parse Sito in query composte. Il codice sopra può essere trasposto nel tuo caso d'uso e applicato usando il metodo di url codificato specificato in precedenza.

compound-query

Nota Bene

Si noti che l'esempio seguente mostra il recupero dei relativi oggetti multipli (usando $ inquery). Ci sono dei limiti riguardo al numero di oggetti interni che possono essere recuperati. Ho notato che questa è sostanzialmente l'equivalenza di ciò che stai facendo nel codice, quindi spero che l'estrapolazione sia relativamente diretta usando questo esempio.

multiple-objects

Attenzione

Si prega di notare che questa parola di cautela da Parse su quando utilizzare il resto-API.

rest-api-caution

+0

Anche se la tua risposta non è canonica, aiuta in qualche modo. Spero che il sistema automatico di premi ti doni la taglia. Ci scusiamo per non essere in grado di assegnarlo da solo. Tuttavia, contrassegnerò la mia risposta come corretta una volta che la inserirò con codice e istruzioni complete. – n00bProgrammer

+0

La risposta è stata aggiornata per rispondere al commento. –

Problemi correlati