37

I have this data structure, where todos are organized to follow path /todos/uid/

{
  "metausers" : {
    "simplelogin:1" : {
      "displayName" : "John Doe",
      "provider" : "password",
      "provider_id" : "1"
    },
    "simplelogin:2" : {
      "displayName" : "GI Jane",
      "provider" : "password",
      "provider_id" : "2"
    }
  },
  "todos" : {
    "simplelogin:1" : {
      "-JUAfv4_-ZUlH7JqM4WZ" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "First"
      },
      "-JUAfveXP_sqqX32jCJS" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : true,
        "subject" : "Second"
      },
      "-JUAfwXnMo6P53Qz6Fd2" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "Third"
      }
    },
    "simplelogin:2" : {
      "-JUAg9rVemiNQykfvvHs" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "Q first"
      },
      "-JUAgAmgPwZLPr2iH1Ho" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : false,
        "subject" : "Q second"
      },
      "-JUAgBfF8f7V5R5-XgrY" : {
        "completed" : false,
        "done" : false,
        "group" : false,
        "private" : true,
        "subject" : "Q third"
      }
    }
  }
}

and i would like to query todos to get all records with private:true. Is this possible using firebase (angularfire) and how should i do it ? Or should i denormalize a bit more and arrange path /private to avoid of walking down todos ?

UmarZaii
  • 1,355
  • 1
  • 17
  • 26
Denis
  • 373
  • 1
  • 3
  • 8
  • 1
    Firebase can query data based on either the name of the node, or the priority of the node. If your `private` property is neither of those, you'll have to either promote it to such (e.g. by calling `setPriority` with the value of `private` for each node) or you'll have to provide an index that provides a list of the data by value (e.g. a node with the names of all non-private todo's). See https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html, https://www.firebase.com/blog/2013-10-01-queries-part-one.html and https://www.firebase.com/blog/2014-01-02-queries-part-two.html – Frank van Puffelen Aug 12 '14 at 22:07
  • 1
    Hi @Denis, my solution below should work for you. I imported your JSON into Firebase to check. Not sure why no one mentioned this. Would be great if you could update the answer for future people (like me) who land here. – Matt Mar 11 '16 at 15:18
  • Maybe .orderByChild was not available in 2014 but it is certainly available in 2020 and it works. Thanks Matt! – ProfDFrancis Nov 13 '20 at 04:09

3 Answers3

57

Assuming you have the uid, this should be straightforward with the following:

var uid = "simplelogin:1";
var todosRef = new Firebase("https://yourdb.firebaseio.com/todos/" + uid);
var privateTodosRef = todosRef.orderByChild("private").equalTo(true);
var privateTodos;

privateTodosRef.on("value", function(response) {
  privateTodos = response.val();
});

This should return an object with all of this user's private todos, organized by their todo key (ie "-JUAfv4_-ZUlH7JqM4WZ". If you'd like to use Angularfire you can wrap this in a $firebaseArray and assign it as follows:

$scope.privateTodos = $firebaseArray(privateTodosRef);

Here's a reference for more info on complex queries, and as mentioned in the other responses there are some nice optimizations that can be done with priorities and restructuring.

Happy coding!

Mechlar
  • 4,946
  • 12
  • 58
  • 83
Matt
  • 5,800
  • 1
  • 44
  • 40
  • 5
    This is exactly what the TS (and I) were looking for. Please upvote as this should be the correct answer! – Boy Jun 02 '16 at 13:01
  • Actually, this is the only way if found for filtering data. Semantically it is not consistent, since there is no sign in the syntax about the filtering. I think Firebase lacks a lot of real word functionality as yet. It is not realistic to build complex data structures with every possible querying situation in mind at the beginning. – Daniel Leiszen Jan 15 '17 at 21:00
  • You may also have to add an indexOn field in the database rules https://firebase.google.com/docs/database/security/indexing-data – Prajoth May 21 '17 at 21:11
17

There are no WHERE clauses in Firebase. Check out this thread for some great structural tips on searching by multiple fields, this thread on database style queries, this blog on queries, and the docs.

Your first approach should be to segment data how it will be read back. Something like the following:

/todos/public
/todos/private
/todos/completed

You can also utilize priorities as explained in the docs. Then fetch items based on priority.

If the list is less than a thousand, which it should be if data is properly partitioned, you can probably just grab the todo list and filter it at the client as well--a great option for short collections like this, particularly when working with a great binding lib like Angular.

Community
  • 1
  • 1
Kato
  • 40,352
  • 6
  • 119
  • 149
  • Thank you Kato for answer and links to threads. Yes, i am working with angular and i plan to use your helper utility too. I know i can grab all list like a array and filtr it if not too big. I only don`t want focus on one point but trying find out other approaches too. – Denis Aug 13 '14 at 08:21
3

All data in Firebaase can be accessed by URLs. If you go to your the Firebase dashboar to view your data model (Forge) and click on the property you are interested in you would be redirected to a URL by which you can access this particular data, e.g. https://myapp.firebaseio.com/todos/simplelogin:1/-JUAg9rVemiNQykfvvHs/private. Keeping this in mind you can access this data with AngularFire.

Alexander Burakevych
  • 2,396
  • 1
  • 24
  • 25
  • Thank you, Alex for your answer. Yes, i think that after yours,Kato`s and Frank`s answers, i have good overview for next study and how to think about denormalization . – Denis Aug 13 '14 at 08:26