Получить список связанных элементов списка элементов в массиве firebase

Я хочу получить список элементов в firebase, но каждый элемент элемента имеет список связанных элементов. Мне не удалось получить список, не используя firebase-util, а также массив firebase $extend.

Данные моей базы данных выглядят примерно так:

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/..."

И я просто хочу получить список элементов со всеми данными. Что-то вроде:

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/..."

Это похоже на довольно распространенный случай использования, но я застрял здесь. Я пробовал это решение (в обоих направлениях), но я не мог заставить его работать. Структура данных также немного отличается, поскольку мне нужно связать список, который находится внутри другого списка.

Ответ 1

Спасибо @Jay и @Eric за ответы, они были очень полезны, у моего решения есть и то, и другое. Я объясню, как я это понял.

Во-первых, я изменил схему и добавил новый ключ для основного изображения элемента. Я назвал его cover. Но, отвечая на исходный вопрос, я сделаю это, загрузив все изображения. Итак, вот новая схема items:

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

Затем я получаю список, упомянутый выше (используя async). Это может быть лучший подход к достижению того же:

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

И это выведет что-то вроде:

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/..."

Ответ 2

Цель состоит в том, чтобы показать список элементов.

Каждый элемент имеет список изображений.

Изначально покажите список элементов и одно из изображений для каждого элемента.

Предлагаемый подход:

Чтобы заполнить список элементов и их начальные эскизы, нам нужно иметь отдельный node, из которого мы извлекаем исходную настройку.

Обновленные элементы node

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/..."

Здесь node используется для основного списка, где пользователь может нажать на палец элемента, чтобы получить более подробную информацию:

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"

Когда приложение запустится, заполните список из items_list_for_ui node.

node является неглубоким и содержит Firebase item_id, имя элемента (если необходимо), ссылку для получения начальной эскиза изображения и ссылку_ основного изображения в Firebase.

Например: если пользователь нажимает миниатюру для пункта 2, данные элемента могут быть загружены функцией наблюденияSingleEvent с .value в

/items/item_id_xx/images/image3

Вы можете изложить это, добавив, например, ссылку на опрокидывание 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"

Эта структура очень гибкая в том, что вы можете изменить, какие палец и опрокидывания вы хотите отображать в основном списке, просто обновив соответствующие дочерние узлы.

Он также эффективен, поскольку он позволяет избежать загрузки сотен предметов и сотен узлов дочерних образов - загрузка всех этих узлов и дочерних узлов приведет к перегрузке ui (в некоторых случаях).

В этой структуре item_list_for_ui является компактным, поэтому даже с сотнями элементов это небольшое подмножество этих данных.

Вы, вероятно, говорите себе, что дублируете данные. Да, это так, и дублирование данных в Firebase является нормальным процессом и поощряется: он сохраняет структуру более плоской и делает запросы и работу с данными намного быстрее.

Подробнее читайте в разделе Денормализация данных держит ваше дыхание Minty Fresh

Ответ 3

Если у вас есть все эти данные, вы можете прокручивать изображения и использовать свои метаданные в качестве ключей в остальной части базы данных.

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

Что должно выдать массив объектов, выглядящих следующим образом:

{
    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/..."
    }]
}