If you have users and comments, you can easily model them as follows:
ROOT | +-- vzhen | | | +-- Vzhen comment 1 | | | +-- Vzhen comment 2 | +-- Frank van Puffelen | +-- Frank comment 1 | +-- Frank comment 2
However, it is more likely that there is a third object, such as an article, and that users comment on the articles (of each other).
Firebase does not have a foreign key concept, but it is easy to simulate. If you do this, you can model the user / article / comment structure as follows:
ROOT | +-- ARTICLES | | | +-- Text of article 1 (AID=1) | | | +-- Text of article 2 (AID=2) | +-- USERS | | | +-- vzhen (UID=1056201) | | | +-- Frank van Puffelen (UID=209103) | +-- COMMENTS | | | +-- Vzhen comment on Article 1 (CID=1) | | | +-- Frank response (CID=2) | | | +-- Frank comment on article 2 (AID=2,UID=209103) | +-- ARTICLE_USER_COMMENT | +-- (AID=1,UID=1056201,CID=1) | +-- (AID=1,UID=209103,CID=2) | +-- (AID=2,UID=209103,CID=3)
This is a pretty direct comparison of how you model it in a relational database. The main problem with this model is the number of searches that you will need to get the necessary information for one screen.
- Read the article (from the article ARTICLE node)
- Read comment information (from ARTICLE_USER_COMMENT node)
- Read the content of the comments (from the COMMENT node)
Depending on your needs, you may also need to read USERS node.
And keep in mind that Firebase does not have the concept of a WHERE clause that allows you to select only items from ARTICLE_USER_COMMENT that match a specific article or specific user.
In practice, this way of displaying the structure is not applicable. Firebase is a hierarchical data structure, so we need to use unique capabilities that give us a more traditional relational model. For example: we do not need the ARTICLE_USER_COMMENT node, we can just store this information directly under each article, user and the comment itself.
A small snippet of this:
ROOT | +-- ARTICLES | | | +-- Text of article 1 (AID=1) | . | | . +-- (CID=1,UID=1056201) | . | | +-- (CID=2,UID=209103) | +-- USERS | | | +-- vzhen (UID=1056201) | . | | . +-- (AID=1,CID=1) | . | +-- COMMENTS | +-- Vzhen comment on Article 1 (CID=1) | +-- Frank response (CID=2) | +-- Frank comment on article 2 (CID=3)
Here you can see that we are distributing information from ARTICLE_USER_COMMENT over the article and user sites. This slightly denormalizes the data. As a result, we will need to update several nodes when the user adds a comment to the article. In the above example, we will need to add the comment itself, and then the nodes to the corresponding user node and article node. The advantage is that we have fewer nodes to read when we need to display data.
If you make this denormalization the most extreme, you will get a data structure like this:
ROOT | +-- ARTICLES | | | +-- Text of article 1 (AID=1) | | | | | +-- Vzhen comment on Article 1 (UID=1056201) | | | | | +-- Frank response (UID=209103) | | | +-- Text of article 2 (AID=2) | | | +-- Frank comment on Article 2 (UID=209103) | +-- USERS | +-- vzhen (UID=1056201) | | | +-- Vzhen comment on Article 1 (AID=1) | +-- Frank van Puffelen (UID=209103) | +-- Frank response (AID=1) | +-- Frank comment on Article 2 (AID=2)
You can see that we got rid of the COMMENTS and ARTICLE_USER_COMMENT nodes in this last example. All information about the article is now stored directly in the node article itself, including comments on this article (with a "link" to the user who made the comment). And all information about the user is now stored under this user node, including comments made by the user (with a "link" to the article about which there is a comment).
The only thing that is still complicated in this model is that Firebase does not have an API to go through such "links", so you have to search for the user / article yourself. It becomes a lot easier if you use the UID / AID (in this example) as the node name that identifies the user / article.
So this leads to our final model:
ROOT | +-- ARTICLES | | | +-- AID_1 | | | | | +-- Text of article 1 | | | | | +-- COMMENTS | | | | | +-- Vzhen comment on Article 1 (UID=1056201) | | | | | +-- Frank response (UID=209103) | | | +-- AID_2 | | | +-- Text of article 2 | | | +-- COMMENTS | | | +-- Frank comment on Article 2 (UID=209103) | +-- USERS | +-- UID_1056201 | | | +-- vzhen | | | +-- COMMENTS | | | +-- Vzhen comment on Article 1 (AID=1) | +-- UID_209103 | +-- Frank van Puffelen | +-- COMMENTS | +-- Frank response (AID=1) | +-- Frank comment on Article 2 (AID=2)
I hope this helps to understand hierarchical data modeling and the trade-offs associated with it.