2016-04-29 19 views
11

Chcę uzyskać listę przedmiotów w bazie ogniowej, ale każdy element elementu ma listę powiązanych elementów. Nie udało mi się uzyskać listy, ani przy użyciu funkcji firebase-util ani funkcji bazy ogniowej $extend.Pobierz pokrewną listę przedmiotów z listy przedmiotów w bazie ogniowej.

Moja Firebase dane wygląda mniej więcej tak:

items 
    item1 
     name: "Item 1" 
     user: user1 
     images 
      image1: true 
      image2: true 
    item2 
     name: "Item 2" 
     user: user1 
     images: 
      image3: true 
      image4: true 
    item3 
     name: "Item 3" 
     user: user2 
     images: 
      image5: true 
      image6: true 

users 
    user1 
     name: "User 1" 
     email: "[email protected]" 
    user2 
     name: "User 2" 
     email: "[email protected]" 

images 
    image1 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 
    image2 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 
    image3 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 
    image4 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 
    image5 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 

A ja po prostu chce uzyskać listę elementów ze wszystkimi danymi. Coś takiego:

items 
    item1 
     name: "Item 1" 
     user 
      name: "User 1" 
      email: "[email protected]" 
     images 
      image1 
       image: "data:image/jpeg;base64,/9j/..." 
       thumb: "data:image/jpeg;base64,/9j/..." 
      image2 
       image: "data:image/jpeg;base64,/9j/..." 
       thumb: "data:image/jpeg;base64,/9j/..." 
    item2 
     name: "Item 2" 
     user 
      name: "User 1" 
      email: "[email protected]" 
     images 
      image3 
       image: "data:image/jpeg;base64,/9j/..." 
       thumb: "data:image/jpeg;base64,/9j/..." 
      image4 
       image: "data:image/jpeg;base64,/9j/..." 
       thumb: "data:image/jpeg;base64,/9j/..." 
    item3 
     name: "Item 3" 
     user 
      name: "User 2" 
      email: "[email protected]" 
     images 
      image5 
       image: "data:image/jpeg;base64,/9j/..." 
       thumb: "data:image/jpeg;base64,/9j/..." 
      image6 
       image: "data:image/jpeg;base64,/9j/..." 
       thumb: "data:image/jpeg;base64,/9j/..." 

Wygląda na dość powszechny przypadek użycia, ale utknąłem tutaj. Próbowałem rozwiązanie this (w obie strony), ale nie mogłem go uruchomić. Struktura danych również jest nieco inna, ponieważ muszę odnieść się do listy znajdującej się na innej liście.

+0

Jak to jest, nie można odzyskać dane w formacie prosicie opartemu na obecna struktura. Czy możesz podać informacje, dlaczego chcesz uzyskać WSZYSTKIE te dane jednocześnie? Zazwyczaj otrzymasz listę nazw użytkowników lub listę zdjęć, które pasują do pozycji 3, ale zazwyczaj nie wszystkie naraz. Myślę, że może istnieć rozwiązanie twojego pytania i zrozumienie, jak pomoże to użycie. – Jay

+0

@Jay chcę wyświetlić listę przedmiotów. Każdy element ma listę obrazów, ale ja po prostu pokażę jeden z nich na liście jako główne zdjęcie przedmiotu. A dlaczego nie, może po najechaniu myszką chciałbym zmienić na inny. Ale przynajmniej gdybym mógł to zrobić z jednym, byłoby miło. – cor

Odpowiedz

2

Dzięki @Jay i @Eric dla odpowiedzi, były one bardzo pomocne, moje rozwiązanie ma po trochu. Wyjaśnię, jak to rozgryzłem.

Po pierwsze, zmieniłem schemat i dodałem nowy klucz do głównego obrazu przedmiotu. Nazwałem to: cover. Ale odpowiadając na oryginalne pytanie, zrobię to ładując wszystkie obrazy. Więc tutaj jest nowy items schematu:

items 
    item1 
     name: "Item 1" 
     user: user1 
     cover: image1 
     images 
      image1: true 
      image2: true 
    item2 
     name: "Item 2" 
     user: user1 
     cover: image3 
     images: 
      image3: true 
      image4: true 
    item3 
     name: "Item 3" 
     user: user2 
     cover: image5 
     images: 
      image5: true 
      image6: true 

Potem, to jak mogę uzyskać listę wymienioną powyżej (przy użyciu async bibliotekę). To może być lepsze podejście do osiągnięcia takie same:

getItems: function(cb){ 
    var items = ref.child("items"); 
    items.on("value", function(snapshot){ 

     var item_length = snapshot.numChildren(), 
      final_items = [], 
      readed = 0; 

     ref.child("items").on("child_added", function(item){ 

      var item_id = item.key(), 
       itemData = item.val(), 

       user = ref.child("users").child(itemData.user), 
       cover = ref.child("images").child(itemData.cover), 
       images = new Firebase.util.NormalizedCollection(
         [ref.child("items").child(item_id).child("images"),'alertImages'], 
         ref.child('images') 
       ).select('images.image','images.thumb').ref(); 

       async.parallel([ 
        function(callback){ 
         user.on("value", function(user_snap){ 
          callback(null, user_snap.val()); 
         }); 
        }, 
        function(callback){ 
         images.on("value", function(images_snap){ 
          callback(null, images_snap.val()); 
         }); 
        }, 
        function(callback){ 
         cover.on("value", function(cover_snap){ 
          callback(null, cover_snap.val()); 
         }); 
        } 
       ], function(err, results){ 
        if(!!err){ 
         cb(err,null) 
        }else{ 
         itemData.user = results[0]; 
         itemData.images = results[1]; 
         itemData.cover = results[2]; 

         final_items.push(itemData); 
         readed += 1; 
         if(readed === item_length){ 
          cb(null,final_items); 
         } 
        } 
       }); 
     }); 
    }); 
} 

i będzie to wyjście coś takiego:

item1 
    name: "Item 1" 
    cover: 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 
    user 
     name: "User 1" 
     email: "[email protected]" 
    images 
     image1 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
     image2 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
item2 
    name: "Item 2" 
    cover: 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 
    user 
     name: "User 1" 
     email: "[email protected]" 
    images 
     image3 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
     image4 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
item3 
    name: "Item 3" 
    cover: 
     image: "data:image/jpeg;base64,/9j/..." 
     thumb: "data:image/jpeg;base64,/9j/..." 
    user 
     name: "User 2" 
     email: "[email protected]" 
    images 
     image5 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
     image6 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
+0

Cieszę się, że masz rozwiązanie. Miej oko na te asynchroniczne połączenia wewnątrz innych asynchronicznych wywołań. Może to sprawić ci kłopoty, więc często sprawdzałbym twoje dane - szczególnie za pomocą funkcji push() i testowania na kilku urządzeniach odczytujących/zapisujących dane mniej więcej w tym samym czasie. – Jay

+0

Dzięki za radę @Jay, szukałem jakiegoś kodu takiego w odpowiedziach, nie tylko o strukturze kodu. W tej chwili nie znalazłem nic lepszego. Będę jednak próbował – cor

4

Celem jest wyświetlenie listy przedmiotów.

Każdy element ma listę obrazów.

Początkowo wyświetl listę artykułów i jedno zdjęcie dla każdej pozycji.

sugerowanego podejścia:

Aby zapełnić listę elementów i ich początkowych miniatury, musimy mieć oddzielny węzeł, który wyciągnie z wstępną konfigurację.

Zaktualizowane elementy węzłowe

items: 
    item_id_xx: //this should be a Firebase generated node name 
    name: "Item 2" 
    user: "uid_for_user_1" 
    images: 
    image3: "data:image/jpeg;base64,/9j/..." 
    image4: "data:image/jpeg;base64,/9j/..." 

Oto węzeł używany do listy głównej, gdzie użytkownik może kliknąć na kciuk artykuł, aby uzyskać więcej szczegółów:

item_list_for_ui 
    random_node_0 
    item_id: "item_id_aa" 
    name: "Item 1" //if you want to display the name in the list 
    initial_thumb: "data:image/jpeg;base64,/9j/..." //initial thumb 
    link_to: "image1" 
    random_node_1 
    item_id: "item_id_xx" 
    name: "Item 2" 
    initial_thumb: "data:image/jpeg;base64,/9j/..." 
    link_to: "image3" 
    random_node_2 
    item_id: "item_id_qq" 
    name: "Item 3" 
    initial_thumb: "data:image/jpeg;base64,/9j/..." 
    link_to: "image1" 

Po uruchomieniu aplikacji, wypełnienia pól lista z węzła items_list_for_ui.

Węzeł jest płytki i zawiera Firebase item_id, nazwę przedmiotu (jeśli jest potrzebna), link do uzyskania miniatury obrazu początkowego i link_to głównego obrazu w Firebase.

Na przykład: Jeśli użytkownik kliknie miniaturę pkt 2, dane pozycji mogą być ładowane przez observeSingleEvent z .Value na

/szt/item_id_xx/images/Image3

Można wykładać na ten temat dodając powiedzmy link rollover do item_list_for_ui

random_node_1 
    item_id: "item_id_xx" 
    name: "Item 2" 
    initial_thumb: "data:image/jpeg;base64,/9j/..." 
    thumb_link: "image3" 
    rollover_thumb: "external link to rollover" 
    rollover_link: "image4" 

struktura ta jest bardzo elastyczny, że można zmienić, co kciuk i najazdy chcesz wyświetlić na liście głównej po prostu aktualizując te poszczególne węzły potomne.

Jest również skuteczny, ponieważ pozwala uniknąć ładowania setek elementów i setek węzłów obrazu podrzędnego - ładowanie wszystkich tych węzłów i węzłów potomnych spowodowałoby przeciążenie interfejsu użytkownika (w niektórych przypadkach).

Dzięki tej strukturze item_list_for_ui ma niewielkie rozmiary, więc nawet z setkami pozycji jest to niewielki podzbiór danych.

Prawdopodobnie mówisz do siebie, to duplikat danych.Tak, a duplikowanie danych w Firebase jest normalnym procesem i zachętą: utrzymuje strukturę bardziej płaską i sprawia, że ​​zapytania i praca z danymi jest znacznie szybsza.

Więcej czytania zobaczyć Denormalizing Data Keeps Your Breath Minty Fresh

+0

Dzięki za odpowiedź @Jay. Ale jak dołączyć do danych? czy używałbyś wtyczki 'firebase-util'? Jeśli tak to jak? Nie wiem, jak to zrobić, ponieważ identyfikator elementu jest dynamiczny. – cor

+0

@cor Firebase nie ma funkcji łączenia, ponieważ nie jest to SQL. Istnieje wiele sposobów powiązania danych, a powielanie danych jest w Firebase w porządku. Myślę, że moja odpowiedź odpowiedziała na twoje bezpośrednie pytanie. Twój komentarz/kontynuacja jest świetnym nowym pytaniem (i jest kilka odpowiedzi, które adresują to już na Stackoverflow). Sprawdź te odpowiedzi, a jeśli masz konkretne pytanie, opublikuj to! – Jay

+0

Przepraszam, masz rację – cor

2

Jeśli masz wszystkie dane dostępne mogłeś pętli obrazów i użyć jej jako metadane klucze w pozostałej części bazy danych.

var itemsArr = []; 
    for(var i in items) { 
     var item = items[i]; 
     var images = []; 
     for(var image in item[images]) { 
      item.push(images[image]); 
     } 
     itemsArr.push({ 
      name: item.name, 
      user: users[item.user], 
      images: images 
     }); 
    } 

Która powinna przynieść tablicę obiektów wygląda tak:

{ 
    name: "Item 1", 
    user: { 
     name: "User 1", 
     email: "[email protected]" 
    }, 
    images: [{ 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
     },{ 
      image: "data:image/jpeg;base64,/9j/..." 
      thumb: "data:image/jpeg;base64,/9j/..." 
    }] 
} 
+0

Wielkie dzięki @Eric N, twoja odpowiedź była pomocna dla tego, co chciałem osiągnąć – cor