Structuring Relationships in Firebase

realph picture realph · Jan 12, 2015 · Viewed 11.7k times · Source

I've got two items in my Firebase: providers and services, and I'm trying to figure out the best way to structure and build relationships using Firebase's recommended flattened architecture approach.

My data looks something like this:

{
  "services" : {
    "hip_replacement" : {
      "title" : "Hip Replacement"
    }
  },

  "providers" : {
    "the_blue_hospital" : {
      "title" : "The Blue Hospital"
    }
  }
}

I would like to link these two items together so that if you were to visit the Hip Replacement page, The Blue Hospital would show up underneath it, if you were to visit The Blue Hospital page, Hip Replacement would show up underneath that. A two-way relationship, essentially.

What would be the best way to structure something like this? I was thinking along the following lines:

{
  "services": {
    "hip_replacement": {
      "title": "Hip Replacement",
      "providers": {
        "the_blue_hospital": true,
        "the_red_hospital": true
      }
    },
    ...
  },
  "providers": {
    "the_blue_hospital": {
      "title": "The Blue Hospital",
    },
    "the_red_hospital": {...
    },
    "the_green_hospital": {...
    }
  }
}

Is there a better way to achieve this or a more elegant solution? Any help is appreciated.

Thanks in advance!

Answer

James picture James · Jan 12, 2015

The problem with joined data in Firebase is that you optimize for certain read or update use cases at the expense of others. In your sample above, creating or deleting a relationship between services and providers requires two separate updates to each "table". There's really nothing wrong with that, but it's not the only way to go.

For a modestly sized data set, you could have a "join table" that maps services to providers, similar to what might be done in the relational DB world. The data might look something like this:

{
  "services": {
    "hip_replacement": {}
  },
  "providers": {
    "the_blue_hospital": {...},
    "the_red_hospital": {...},
    "the_green_hospital": {...}
  },
  "serviceProviders": {
    "-JqD5JX0RUDTXsu7Ok3R": {
      "provider": "the_blue_hospital",
      "service": "hip_replacement"
  }
    "-JqDoKfyJqPkQlCXDvFM": {
      "provider": "the_green_hospital",
      "service": "hip_replacement"
  }
    "-JbE7Ji_JRz2bHgBdMWQ": {
      "provider": "the_blue_hospital",
      "service": "hip_replacement"
  }
}

There are pros and cons of this approach:

Pro

  • Easy to add mappings in one place
  • Easy to delete mappings in one place
  • Flexible options to reformat the data for display, beyond the context of a single provider or service, such as an index.

Con

  • You have load the whole data set. Firebase doesn't let you filter within a key, clients have to load the whole list, then filter in memory. I suspect this will work fine for hundreds of records, anyways, maybe for low thousands.
  • You have to do some client work to filter the list for display and merge it with the actual service and provider data. Again, if the data set isn't too big, underscore/lodash groupBy() can make short work of this.

You should consider:

  • How much updating and deleting will you do?
  • Is the join information really that simple? Would you need more records (display names, prices, etc.) that make maintenance on the join table more complicated than I suggested?