3
votes

I am building an app using Firebase and am having trouble structuring the data for a hierarchy that my app needs.

Concept

My app consists of items. Each item can have n-many child items. There will be 100s of thousands of items in the database and for any given item. I want to get a count of all child items (i.e.: direct children, grand children, great grandchildren, etc).

Current structure example

items: { 
   1: {
       name: 'neat item 1'
   },
   2: {
       name: 'neat item 2',
       parentId: 1
   },
   3: {
       name: 'neat item 3',
       parentId: 2
   }
}

Question

In Firebase, what is the best way to track the number of children an item has? So in the example above, item #1 has a total 2 children, item #2 has a total of 1 child.

Would it be best to maintain a childCount on each item and whenever a new item is added, increment that number for all parents? Or would it be better to recursively compute the child count whenever it's needed?

Keeping in mind that there will be 500,000+ items in the database, with some items having a total of 10,000+ children.

Thanks so much for your time!

1

1 Answers

2
votes

In Firebase (as in most NoSQL databases) you should model the data for the way your app uses it (I highly recommend reading this article on NoSQL data modeling for more pieces of wisdom).

An important thing to realize is that Firebase always loads the entire node, including all data under that node. There's no way (within the SDKs) to load so-called shallow data.

So if your app always shows the entire tree, than you can definitely model the data as a tree.

But given the size of the tree, it is much more likely that you're going to show one level at a time and then allow the user to click to expand that level. If you'd model the data as a hierarchy, you'd end up loading all children of a node, even when the user never expands that node. That is wasteful.

So more common is to store the hierarchy as a list, pretty similar to how you'd store it in a relational database. You'd then keep a separate list of children of each node. Note that this is a list, not a tree.

nodes
  nodeKey1
    name: "Node 1"
    childrenCount: 2
  nodeKey2
    name: "Node 2"
    childrenCount: 1
    parentKey: "nodeKey1"
  nodeKey3
    name: "Node 3"
    childrenCount: 0
    parentKey: "nodeKey1"
  nodeKey4
    name: "Node 4"
    childrenCount: 0
    parentKey: "nodeKey2"
nodeChildren
  nodeKey1
    nodeKey2
    nodeKey3
  nodeKey2
    nodeKey4

This allows for efficient reading/querying of:

  • the list of top-level nodes (ref.orderByChild('parentNode').equalTo(null))
  • the metadata for a specific node
  • the parent of a specific node
  • the children of a specific node

If you have more use-cases, you may need to expand the data model.