0

I am trying to fetch a list from firebase that has an array of email addresses. I only want the items that matches the email in the query. Here is the structure. I am trying to fetch items that match test1@gmail.com under collaborators

enter image description here

The query:

this.firebase.list('/todo', {
        query: {
            orderByChild: 'collaborators',
            equalTo: 'test1@gmail.com'
        }
    }).subscribe((data)=>{
        console.log(data);
    });

This return empty array which is supposed to list one item!

How do I solve this..

Solution:

let results = this.firebase.list('/todo')
        .map(data => data.filter( (e) => {
            return e.collaborators.indexOf(email) > -1;
        }
    ));
    return results
Ashik Basheer
  • 1,531
  • 3
  • 16
  • 36

1 Answers1

1

You're trying to access the email address as if it was a value of collaborators. In fact, the email address is a value of one of its children.

I'd suggest restructuring your model to use the email as the key rather than the value; e.g., test1@gmail.com: true. I mentioned some of the advantages of this and offered a couple of links that cover the topic in my comment below.

After this minor alteration to your model, use the map operator to map to collaborators and use the filter operator to filter out objects whose collaborators object contains a property whose key matches email.

getNotesFromSpecifiedUser(email: string): Observable<any> {
    let results = this.af.database.list('/todo')
    .map(data => data.filter(data => (email in data.collaborators)))
    return results
}

Important: If there are no entries in collaborators an error will be thrown because the in keyword cannot handle null. If it's conceivable that collaborators will be empty, let me know.

J. Adam Connor
  • 1,694
  • 3
  • 18
  • 35
  • I get this error `this.firebase.list(...).map is not a function` – Ashik Basheer Mar 06 '17 at 23:11
  • 1
    You need to import the operator. `import 'rxjs/add/operator/map'` – J. Adam Connor Mar 06 '17 at 23:12
  • this returns an empty array – Ashik Basheer Mar 06 '17 at 23:26
  • I made a small change that worked for me ! Accepting answer for giving the hint of using map and filter – Ashik Basheer Mar 06 '17 at 23:36
  • You'll have to subscribe if you want the observable to emit anything. The `map` operator does not cause the observable to emit anything. It simply alters the potential emissions. See my updated answer for details. – J. Adam Connor Mar 06 '17 at 23:37
  • I did subscribe but `email in data.collaborators` always returned empty. I have updated my question with solution – Ashik Basheer Mar 06 '17 at 23:39
  • Oh, that's my mistake. The `in` keyword actually looks for a key in that matches `email`. This raises a suggestion I have about your model, though. Instead of using `0: test1@gmail.com`, consider `test1@gmail.com: true`. This makes creates a number of opportunities for you in the future, such as the ability to include the email in a path and to access the email using a [shallow query](http://stackoverflow.com/a/37369483/6024090). There are a number of other [advantages to structuring your data](https://firebase.google.com/docs/database/web/structure-data) this way. – J. Adam Connor Mar 07 '17 at 00:03
  • I would like to restructure my data. I have a question though. The solution which we worked on, does it fetch entire '/todo' and then filter locally or does it fetch only filtered data? If the solution brings the whole set of data and filter locally isn't that a potential security issue? because anybody can download the app and modify permissions locally! – Ashik Basheer Mar 07 '17 at 07:54
  • What I mean by permission is the first email in collaborators is the admin of that todo item. So anybody can modify the code right? – Ashik Basheer Mar 07 '17 at 07:56
  • 1
    You never want to rely on client side access restrictions. The paths to your database and its data will always be visible. You have to restrict access through rules. If there is sensitive data anywhere in your database it should be encrypted. – J. Adam Connor Mar 07 '17 at 16:04