2016-01-06 14 views
43

Tak, mam za zadanie wdrożenie „retweet' podobną funkcjonalność w aplikacji (iOS Swift), stosując Parse.parse.com „Prześlij dalej” wzór jest zbyt rozwlekły

Zostało to zadane przed here, ale to jest dość wysoki poziom i b) Dostaję to zadanie pod ręką - niekoniecznie proszę o pomoc w decyzjach architektonicznych, ale jeśli wydaje mi się, że oczywiście brakuje mi coś, jestem szczęśliwy, aby przyjąć opinie.

Moja aplikacja ma PRZYCZYNY, które są tworzone przez UŻYTKOWNIKA. Istnieje również tabela FOLLOW z użytkownikiem TO i użytkownikiem FROM. Na początek po prostu odpytuję tabelę przyczyn, z ograniczeniem, które użytkownik, który wysłał, powinien pasować do ID obiektu użytkownika TO (gdzie bieżący użytkownik jest od użytkownika FROM) w tabeli FOLLOW. Bardziej zwięźle:

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. 
     } 
    } 
}) 

Teraz mam wszystkie przyczyny od użytkowników, których przestrzegam ... to całkiem niezły standard.

Oto, gdzie to staje się trudne.
Każdy Powód ma również Relację zwaną WSPIERAJĄCYMI. Teraz muszę zaprojektować sposób, aby uzyskać wszystkie przyczyny od osób, których nie śledzę, ale które mają na liście ich użytkowników, których obserwuję.

muszę jeszcze znaleźć eleganckie rozwiązanie, choć jestem zbliża się „brute force”, jeden, i to jest tak kłopotliwy i gadatliwy, że lepsza połowa mózgu mojego programatora jest screaming at me like Susan Powter ...

Oto próbka:

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 
           } 
          } 
         }) 
        } 
       } 
      } 
     } 
    } 
}) 

teraz, to jest czyste szaleństwo, a niezwykle rozrzutny (szczególnie biorąc pod uwagę jak Parse oblicza wolną Poziom - czuję, że to naprawdę może przyczynić się w dużym stopniu do mojego limitu API jeśli wciśnięty do produkcji).

Mając już wykonane dwa zapytania, ja przerobić jeden całkowicie, a następnie wykonaj kolejne zapytanie dla każdej przyczyny na Stosunków zwolennikiem, a następnie wykonaj kolejne zapytanie o każdego użytkownika w tej relacji, aby zobaczyć, czy ja za nimi ... i kiedy już mam te informacje, muszę przejrzeć te obsługiwane przez użytkownika przyczyny (z powodu asynchronicznego zwracania zapytań Parse, nie wydaje mi się, żebym mógł w ogóle wrócić do pętli rodzica) ... które ja jeszcze nie zaimplementowałem, bo mam zamiar rzucić ręcznik - musi być lepszy sposób!

Mam nadzieję, że mi brakuje strategii tutaj ...

+4

Wydaje mi się, że potrzebujemy zwrotne od kibiców do przyczyn, nie? W takim przypadku polecam tabelę łączenia użytkowników USERS z CAUSES, których znajdują się na liście SUPPORTERS.To są tylko dwa pytania - uzyskaj wszystkie moje OBSERWATORA, a następnie uzyskaj przyczyny, dla których każdy UŻYTKOWNIK jest WSPIERAJĄCY, a następnie usuń duplikaty przyczyn. – tbondwilkinson

+1

Tak, to ma sens ... Przeanalizuję to jako opcję. –

+2

Nie znam tej struktury, ale bez zmiany semantyki można nieco uprościć składnię. Zwykle piszę "jeśli pozwalam x = y {dla i wx {..." jak "dla mnie w y? [] {... '. Zastanowiłbym się też nad zastąpieniem 'if error == nil ...' z 'guard error! = Nil else {return}'. Te dwa nie pozwolą ci zaoszczędzić wierszy, ale zaoszczędzą ci kolumn: to zmniejszyłoby twoje najskrytsze '// rzeczy do zrobienia' z 9 poziomów wcięć do 6, co nie jest * całkiem * tak szalone. –

Odpowiedz

1

@ jesses.co.tt Przepraszam, jeśli to zbyt mało i zbyt późno, zdecydowanie wziąć pod uwagę, że to ja odpowiadam kilka miesięcy po tym, jak został poproszony, ale myślę, że to jest warte odpowiedzi w ogóle (i może nadal może być dla ciebie wartościowa).

Ogólnie, w 100% zgadzam się, że to potrójne zapytanie z Parse jest a) będzie bardzo nieefektywne w sposobie jego naliczania (w starym systemie) i b) mając to na uwadze, wydaje się błędne podejście nawet z self-hosted Parse (który jest kontekstualnie jedynym mechanizmem używanym w tym momencie, ponieważ Parse został zamknięty, ale myślę, że byłby prawdopodobnie w stanie, gdy pytanie zadano ... niezależnie ...). Istnieją dwa rozwiązania, które widzę, że można to naprawić w dość czysty sposób, zakładając, że te zmiany można wprowadzić do ogólnego schematu/architektury.

1) pierwszy roztwór jest ponownie schematyczny zestaw danych i zasadniczo klawisz „obcy” podzbiór zwolenników każdy User ma w samej tabeli User. W ten sposób, zamiast przechodzić od Cause -> ->User, teoretycznie będziesz w stanie wykonać Cause ->User (od użytkowników, domyślnie otrzymasz ich wsparcie, ponieważ będzie to kolumna). Aby to zrobić w , jeśli dobrze pamiętam, możesz ustawić kolumnę tak, aby miała pewną tablicę określonego typu, a następnie zawierała linki object (które ładnie się wyświetlają na pulpicie Parse), które są rzeczywistą tabelą Supporter obiektów, ale zachowując tę ​​kolumnę odnośników do tej tabeli w tabeli User.

Choć jest nieco więcej pracy po stronie write, ponieważ będziesz musiał ręcznie zrobić (ręcznie Znaczy zapisu kod samemu to zrobić, powinno być zautomatyzowane, ale nie będzie dzieje się za darmo pod względem rozwoju). Z tym nieco więcej ustalonymi write pracy, wtedy masz 2 Krok read zamiast 3.

2) Drugim rozwiązaniem jest użycie innego dostawcy tego rodzaju danych, jeśli zapytanie jest prędkość problem. W kilku z moich projektów używam gniazd na podstawie podejścia do tego rodzaju odnośnika zapytań danych i myśli jak Pusher lub Firebase (zarówno bardzo różne poziomy „wszystko otwartości” Firebase jest znacznie bardziej jak Parse ale z Google tym razem, Pusher jest nieco bardziej podstawowa i "Zrób to sam").

Z Firebase, na przykład, i gniazdo do tego zestawu danych + schemacie, w którym sama tabela Cause ma cache co User s należą do nich (iw którym User posiada pamięć podręczną ich Supporter s), to 3-etapowe sprawdzenie może być efektywnie 1 zapytaniem z 2 parametrami (co jest moim zdaniem idealnym scenariuszem). Wierzę, że można to osiągnąć również przy użyciu narzędzia Parse, ale wymagałoby to kolejnego kroku do zreorganizowania schematu do pierwszego zaproponowanego rozwiązania.

Myślę, że w komentarzach zaleca się coś podobnego (oba powyższe rozwiązania), ale w znacznie bardziej nieszablonowym formacie. Mam nadzieję, że pomoże to oryginalnemu pytającemu lub komuś. To może też teoretycznie jak ktoś poleca używać PubNub jako 1 komentarz wspomniano, ale może to tylko tak łatwo zbudować ten schemat do PostgreSQL DB hostowane na AWS lub Heroku i wykonać te same mechanizmy jak Parse bez koszty ogólne.

Ponadto, ponieważ jest to w odniesieniu do analizy, która jest obecnie oferowana tylko jako Open Source samo rozwiązanie hostingowe, oto przypomnienie migrować do gospodarzem Parse na własną rękę na AWS: link here

+0

Świetna odpowiedź, wkrótce wrócimy! Dzięki! –