Kerry Jones
Kerry Jones

Reputation: 21838

Firebase - Deep Query orderByChild with equalTo

I am trying to grab every project by the members within them -- I've created a sample datastructure though the actual structure is much larger (as in it would be difficult to restructure the database).

Here is my query:

var ref = new Firebase(FBURL + '/chat/meta/project');

var email = '[email protected]';

ref
    .orderByChild("email")
    .equalTo(email)
    .on("child_added", function(snapshot) {
        console.log(snapshot.val());
    }
);

It is important to note that if I remove the .equalTo(email) that it returns all of the "projects", when it should only return 2 of them.

Here is the data in Firebase:

{
  "chat" : {
    "meta" : {
      "project" : {
        "-KAgjWOxjk80HIbNr68M" : {
          "name" : "Gman Branding",
          "url" : "http://localhost:3000/project/abc123fasd123cc/...",
          "date" : "2015-10-10T21:33:25.170Z",
          "member" : {
            "-KAgkD-2GVESwNwKP3fA" : {
              "email" : "[email protected]"
            },
            "-KAgkP3M4nug9Bjn-vY6" : {
              "email" : "[email protected]"
            },
            "-KAgkP3OF0sUgc9x9p37" : {
              "email" : "[email protected]"
            },
            "-KAgkaMyEOiXft6o-HbO" : {
              "email" : "[email protected]"
            }
          }
        },
        "-KAgl9xlPDU5T4072FgE" : {
          "-KAglqH9pxkhgC84_kAl" : {
            "name" : "YuDog",
            "url" : "http://localhost:3000/project/abc123fasd123cc/...",
            "date" : "2015-10-10T21:41:31.172Z"
          },
          "name" : "billing test 1",
          "url" : "http://localhost:3000/project/abc123fasd123cc/...",
          "date" : "2015-02-25T23:18:55.626Z",
          "dateNotifyUnread" : "2016-01-25T23:23:55.626Z",
          "member" : {
            "-KAglNsswyk66qUZNrTU" : {
              "email" : "[email protected]"
            }
          }
        },
        "-KAgltmLk2oOYhEDfwRL" : {
          "-KAgm1Jt5q53gzLm1GIh" : {
            "name" : "YuDog",
            "url" : "http://localhost:3000/project/abc123fasd123cc/...",
            "date" : "2015-10-10T21:41:31.172Z"
          },
          "name" : "YuDog",
          "url" : "http://localhost:3000/project/abc123fasd123cc/...",
          "date" : "2015-10-10T21:41:31.172Z",
          "member" : {
            "-KAgm1Jvss9AMZa1qDb7" : {
              "email" : "[email protected]"
            }
          }
        },
        "-KAgluTcE_2dv00XDm1L" : {
          "-KAgm6ENmkpDiDG2lqZ4" : {
            "name" : "YuDog Landing Page",
            "url" : "http://localhost:3000/project/abc123fasd123cc/...",
            "date" : "2015-10-10T21:41:31.172Z"
          },
          "-KAgmBptbeInutRzNinm" : {
            "name" : "YuDog Landing Page",
            "url" : "http://localhost:3000/project/abc123fasd123cc/...",
            "date" : "2015-10-10T21:41:31.172Z"
          },
          "name" : "YuDog Landing Page",
          "url" : "http://localhost:3000/project/abc123fasd123cc/...",
          "date" : "2015-10-10T21:41:31.172Z",
          "member" : {
            "-KAgm6EQcvQg3oP-OnIF" : {
              "email" : "[email protected]"
            },
            "-KAgmBpwoxPYGXS9fLZ9" : {
              "email" : "[email protected]"
            }
          }
        }
      }
    }
  }
}

I've looked at 8-10 other links on SO but haven't found any that solve this issue.

Upvotes: 2

Views: 2550

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598740

The solution is to create a data structure that matches your needs. In this case, you want to look up the projects for a user based on their email address. So we'll add a node that contains this mapping:

"projects_by_email": {
  "kerry@email,com": {
    "-KAgjWOxjk80HIbNr68M": true,
    "-KAgl9xlPDU5T4072FgE": true
  },
  "abc@gman,com": {
    "-KAgjWOxjk80HIbNr68M": true
  }
  ...
}

This is called denormalizing your data, although I often think of them as inverted indexes. I would probably keep the projects by uid, but the structure would be the same.

With a structure like this, you can get the list of projects for an email with a simple direct look up:

var ref = new Firebase(FBURL);
var email = '[email protected]';
ref.child('projects_by_email')
   .child(email)
   .on("child_added", function(snapshot) {
       console.log(snapshot.key());
   }
);

Or if you then also want to "join" the projects themselves:

var ref = new Firebase(FBURL);
var email = '[email protected]';
ref.child('projects_by_email')
   .child(email)
   .on("child_added", function(snapshot) {
       ref.child('project').child(snapshot.key()).once('value', function(projectSnapshot) {
           console.log(projectSnapshot.val());
       });
   }
);

This type of denormalizing is a normal part of NoSQL data modeling. The duplication may feel wasteful, but it is part of why NoSQL solution scale so well: none of the code above asks the database to consider all projects/all users. It's all directly accessing the correct nodes, which scales really well. So we're sacrificing storage space to gain improved performance/scalability; a typical space vs time trade-off.

Upvotes: 3

Related Questions