6

I read this question Many to Many relationship in Firebase,
and here describes how to create or structure many to many relationship within firebase(nosql database), and it is pretty easy,

companyContractors
  companyKey1
    contractorKey1: true
    contractorKey3: true
  companyKey2
    contractorKey2: true
contractorCompanies
  contractorKey1
    companyKey1: true,
    companyKey2: true
  contractorKey2
    companyKey2: true
  contractorKey3
    companyKey1: true

but when i want to get all contractors specific company, can i do it using only one request? because in this case i get only list of id, and after there, using js loop, or forEach, i do multiple request.

usually on others API's, i only use

URL/contractor/:id/company or 
URL/company/:id/contractors 

how to do it on firebase?
it would be cool to have an example of using angular2, angularfire2
thanks

AskFirebase

Community
  • 1
  • 1
Limarenko Denis
  • 769
  • 1
  • 8
  • 13
  • No, you will need multiple requests for that. But Firebase requests are pipelined over a single connection and are a lot faster than you may think. See my answer here: http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786 (which I think may be a dupe). – Frank van Puffelen Jan 26 '17 at 09:29
  • Do you know, there is a video about *your* question: https://www.youtube.com/watch?v=HjlQH3RsGcU&feature=youtu.be&t=164s – Balazs Nemeth Apr 02 '17 at 22:07

1 Answers1

3

With NoSQL, you have to think in terms of views first, then let the views dictate your schema. You can definitely do this with one query, but forget about normalization, that concept only applies to relational databases.

Let's say you have a view where you want to search by company and list all the contractors, with their info, or search by contractor and list all the companies with their info:

Schema: companyContractorKey, contractorCompanykey, contractorName, contractorSkill, companyIndustry, etc...

where companyContractorKey is a field containing a concatenation of the company name and contractor name, for example: 'Acme/Ellis Electric'. You can then do a range search from 'Acme/A' to 'Acme/z' and get all the contractors for Acme.

Similarly, contractorCompanyKey is a field containing a concatenation of the contractor name and company, for example 'Ellis Electric/Acme'. You can then do a range search from 'Ellis Electric/A' to 'Ellis Electric/z' to get all the companies for Ellis Electric.

The drawback is that the information for a company is stored in multiple records (easily found using the companyContractorKey), and the information for a contractor is also stored in multiple records (found using the contractorCompanyKey), so updates and deletions will involve multiple records, but querying will be super fast, as long as you indexOn the two key fields. Firebase supports updating multiple records with one request, so this should not present a problem.

Also you will want to avoid putting in all the information about a company or contractor in that schema node, only what is necessary for your views, and have all the details that are not in the "listing" view in separate schema nodes, one dedicated to companies and one to contractors.

Tony BenBrahim
  • 7,040
  • 2
  • 36
  • 49
  • I show /A and /z as range start and end for clarify, but in a real application, I use / and /ASCII 255 – Tony BenBrahim Jan 25 '17 at 22:11
  • Loading the individual items is not as slow as you may think, since Firebase pipelines the requests. See my answer here: http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786. – Frank van Puffelen Jan 26 '17 at 09:28
  • That said, I am personally a big fan of duplicating (part of) the actual data to get rid of the join. But that's mostly for code clarity reasons, not for performance. We say that with Firebase you end up modeling the "view model" in the database, which is similar with what you started with. So we agree on most parts, just not that my answer to the linked question is wrong. :-) – Frank van Puffelen Jan 26 '17 at 10:16
  • I am not familiar with pipelined requests. I am familiar with parallel requests, as shown in the linked post but in that case, I think you will hit the browser limit of maximum concurrent requests to one URL, so you might get 8 or 16 parallel requests at a time depending on the browser. So for a query that returns 64 items, you end up with 1 round trip for the first request and the equivalent of 8 round trips on each socket, for a total of 9 round trips (which would explain the 600 ms latency on a good connection). On mobile, it is not going to be nice...Now with HTTP/2.0, it would be better. – Tony BenBrahim Jan 26 '17 at 14:35
  • 1
    It's a single connection, so there's no maximum. It uses web sockets, so there's no HTTP overhead (beyond the initial first request for the connection). The post I linked, as it explains how it works. It also includes a link to a jsbin that you can use to test it. – Frank van Puffelen Jan 26 '17 at 14:48
  • Learn something every day, thank you for the clarification, I will correct my post – Tony BenBrahim Jan 26 '17 at 20:58
  • Thanks for that. Now I can upvote. :-) Like I said: most of your content was great already, some of it just works very differently in Firebase. – Frank van Puffelen Jan 26 '17 at 21:22