Introduction

So I have been playing with Firebase with a couple of prototypes and projects for quite some time. I have used React JS for a conference websitethat I co-managed and Polymer for a couple of prototypes that I am currently working on. After coming from using MongoDB and MySQL/PostgreSQL, information structure, storage and retrieval is very different in Firebase than with the two.

  • a “member” can only create / edit / delete their Comment.
  • a “contributor” can do any functionalities the “member” can, and also create / edit / delete their own Article.
  • an “editor” can do any functionalities the “member” and “contributor” can, and can set any Article to be published and be seen by all. They can also give promote any “member” into a “contributor” as well.
  • an “admin” can do all of the above, and also can promote any “member”, “contributor”, or “editor” into an “editor” or “admin”.
  • An Article can only have one author (as of the moment, more on this later), but has many Comments.
  • An Article will only be viewed by all if it is published (published == true), or will only be viewed by the “admin”, “editor” or the owner if it is not published.
  • An Article can be found using the slug_name, which is the “slugified” title or the Article plus random characters for uniqueness.
{
"user": {
"user1": {
"uid": "user1",
"firstname": "Jack",
"lastname": "Mayer",
"email": "jack_mayer@email.com",
"date_joined": 1333065600000
"role": "admin"
},
"user2": {
"uid": "user2",
"firstname": "Stef",
"lastname": "Gomez",
"email": "stef_gomez@email.com",
"date_joined": 1333065600000
"role": "contributor"
},
"user3": {...},
...
},
"article": {
"article1": {
"article_id": "article1",
"slug_name": "this-is-an-article-abcdef",
"uid": "user1",
"title": "This is an Article",
"body": "This is the body of the article."
"published": 1,
"date_edited": 1333065600000,
"date_created": 1333065600000
},
"article2": {...},
...
},
"comment": {
"comment1": {
"comment_id": "comment1",
"uid": "user2",
"article_id": "article1",
"body": "this is a comment",
"date_edited": 1333065600000,
"date_created": 1333065600000
},
"comment2": {...},
...
}
}

Firebase Retrieval and Rules

Now let’s say you want to list all Articles that are published but not show the Articles that are not published.

var Article = mongoose.model('Article', yourSchema);  Article.find({ published: true }, function (err, articles) {
// list all articles here
})
var articles = []firebase.database().ref('/article').orderByChild('published')
.equalTo(1).on('child_added', function(data) {
articles.push({
id: data.key,
data: data.val()
})
})
// Firebase Rules snippet"article": {
"$article": {
".read": "data.child('published').val() == 1"
}
}
// Firebase Rules snippet"article": {
".read": true,
"$article": {
".read": "data.child('published').val() == 1"
}
}

A New List Structure

To remedy the problem above, we can change the structure a little bit. Instead of this:

{
...
"article": {
"article1": {
"article_id": "article1",
"slug_name": "this-is-an-article-abcdef",
"uid": "user1",
"title": "This is an Article",
"body": "This is the body of the article."
"published": 1,
"date_edited": 1333065600000,
"date_created": 1333065600000
},
"article2": {...},
...
},
...
}
{
"article_group": {
"article": {
"article1": {
"article_id": "article1",
"slug_name": "this-is-an-article-abcdef",
"uid": "user1",
"title": "This is an Article",
"body": "This is the body of the article."
"date_edited": 1333065600000,
"date_created": 1333065600000
},
"article2": {...},
...
},
"article_list": {
"article1": {
"published": 1
}
"article2": {
"published": 0
},
},
},
}
// Firebase Rules snippet"article_group": {
"article": {
"$article": {
".read": "data.parent().parent().child('article_list')
.child($article).child('published').val() == 1"
},
},
"article_list": {
".read": true,
}
}
var articles = []firebase.database().ref('/article_group/article_list')
.orderByChild('published').equalTo(1)
.on('child_added', function(data) {
firebase.database().ref('/article_group/article/' +
data.key).on('value', function(articleData) {
articles.push({
id: data.key,
data: articleData.val()
})
})
})
})
"$article": { 
".read" : "data.parent().parent().child('article_list')
.child($article).child('published').val() == 1"
}
}

Advanced Part: Sorting

Of course, blogs are sorted by date (let’s say date_created). We can change the data structure now to be:

{
"article_group" : {
"article" : {
"article1" : {
"body" : "This is the body of the article",
"date_edited" : 1333065600000,
"slug_name" : "this-is-an-article-abcdef",
"title" : "This is an Article",
"uid" : "user1"
},
"article2" : {
"body" : "This is a new body",
"date_edited" : 1333065600000,
"slug_name" : "article-on-firebase-hijklm",
"title" : "Article on Firebase",
"uid" : "user2"
},
"article3" : {
"body" : "This is a new body",
"date_edited" : 1333065600000,
"slug_name" : "article-on-firebase-hijklm",
"title" : "Article on Firebase",
"uid" : "user2"
}
},
"article_list" : {
"article1" : {
"published" : 1459296000000
},
"article2" : {
"draft" : 1333065600000
},
"article3" : {
"published" : 1461974400000
}
}
}
}
// Firebase Rules snippet"article_group": {
"article": {
"$article": {
".read": "data.parent().parent().child('article_list')
.child($article).child('published').exists()"
},
},
"article_list": {
".read": true,
}
}
var articles = []
var limit = 2firebase.database().ref('/article_group/article_list')
.orderByChild('published').limitToLast(limit)
.on('child_added', function(data) {
if (data.val().published) {
firebase.database().ref('/article_group/article/' +
data.key).on('value', function(articleData) {
articles.push({
id: data.key,
published: data.val().published,
data: articleData.val()
})
if (articles.length == limit) {
sortArticle()
}
})
} else {
console.log('this is not published')
}
})
})// then after getting the necessary data
function sortArticle() {
article.sort(function(a, b) {
return a.published < b.published
})
// show article list in sorted
}

Final Thoughts

We have shown a different way of structuring the data for effective retrieval of filtered lists using Firebase. Next would be using this technique, along with Firebase roles, in creating, saving, publishing, deleting articles. Stay tuned.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store