5

I develop a small web-app based on Vue.js using Firebase to store and sync the data. I store items (e.g. with attributes title and subtitle) and lists with an attribute listitems, where an array of keys (those generated from Firebase) of items is stored. The structure looks like this:

enter image description here

Now the problem: I want to display a list and show the items from the listitems attribute and I'm doing it like this:

Compontent:

var ShowList = Vue.extend({
    template: '#show-list',
    firebase: {
        // get all existing items from firebase
        items: firebase.database().ref('items')
    },
    data: function () {
        // get list item keys of list 'list_id' and bind it to this.list
        this.$bindAsObject('list', listsRef.child(this.$route.params.list_id));
        return {
            list: this.list
        };
    }
});

Template:

<!-- show a list -->
<template id="show-list">
    <ul v-if="list.items != ''">
        <li v-for="key in list.items">        <!-- I would like to not being forced to -->
            <template v-for="item in items">  <!-- iterate the whole list of existing items -->
                <span v-if="item['.key'] == key">
                    {{ item.title }}
                </span>
            </template>
        </li>
    </ul>
    <div v-else>No items.</div>
</template>

As you can see, I have to use two iterations where I iterate the full items list for every entry in list.items.

My question: Is there a more efficient way to map the actual objects to the list of object keys? For a huge number of item records, my approach will be very slow. Maybe I'm just too blind to see a simpler solution?

Thanks for your time!

andreas
  • 16,357
  • 12
  • 72
  • 76

2 Answers2

0

I think you have to denormalize/duplicate some data there. I had a similar situation and this Firebase video cleared a lot of things up for me: https://youtu.be/ran_Ylug7AE?t=2m22s (Link updated to passage at 2:22. The whole serie is worth watching btw.)

My shot at it would be adding (Firebase) keys in "listitems", just like you have done in "items", with only the most crucial data there, so that you can link to a full description

naton
  • 109
  • 7
  • I'm looking for a solution, where I don't have to duplicate the data - duplicated data in databases is hard to maintain. – andreas Apr 25 '18 at 08:16
0

Is your data read only? In which case you could move the filter logic from your template to your data module, like so (I expect I have unintended side-effects):

data: function () {
    // get list item keys of list 'list_id' and bind it to this.list
    this.$bindAsObject('list', listsRef.child(this.$route.params.list_id));
    var items = firebase.database().ref('items')
    var activeItems = this.list.items.map(function(key) {
        return items[key]
    })
    return {
        activeItems: activeItems;
    };
}
Chris Buck
  • 745
  • 5
  • 15
  • Nice idea. The problem here ist, you cannot use `items[key]`, because `items` is a simple list of item objects. An item object has the key as a separate property. The items array looks similar to this: `items = [{"a": "...", "b": "...", ".key": key}, {"a": "...", "b": "...", ".key": key}, ...]` – andreas Jun 27 '18 at 22:42