Jaroslaw K.
Jaroslaw K.

Reputation: 5374

Optimalization of firebase query. Getting data by ids

I'm new in Firebase. I would like to create an app (using Angular and AngularFire library), which shows current price of some wares. I have list all available wares in Firebase Realtime Database in the following format:

"warehouse": {
   "wares": {
      "id1": {
         "id": "id1",
         "name": "name1",
         "price": "0.99"
      },
      "id2": {
         "id": "id2",
         "name": "name2",
         "price": "15.00"
      },
      ... //much more stuff
   }
}

I'm using ngrx with my app, so I think that I can load all wares to store as an object not list because normalizing state tree. I wanted load wares to store in this way:

this.db.object('warehouse/wares').valueChanges();

The problem is wares' price will be refresh every 5 minutes. The number og wares is huge (about 3000 items) so one response will be weight about 700kB. I know that I will exceed limit downloaded data in a short time, in this way.

I want limit the loading data to interesing for user, so every user will can choose wares. I will store this choices in following way:

"users": {
   "user1": {
      "id": "user1",
      "wares": {
          "id1": {
             "order": 1
          },
          "id27": {
             "order": 2
          },
          "id533": {
             "order": 3
          }
      },
      "waresIds": ["id1", "id27", "id533"]
   }
}

And my question is:

Is there a way to getting wares based on waresIds' current user? I mean, does it exist way to get only wares, whose ids are in argument array? F.e.

"wares": {
   "id1": {
      "id": "id1",
      "name": "name1",
      "price": "0.99"
   },
   "id27": {
      "id": "id27",
      "name": "name27",
      "price": "0.19"
   },
   "id533": {
      "id": "id533",
      "name": "name533",
      "price": "1.19"
   }
}

for query like:

this.db.object('warehouse/wares').contains(["id1", "id27", "id533"]).valueChanges();

I saw query limits in Angular Fire like equalTo and etc. but every is for list. I'm totally confused. Is there anyone who can help me? Maybe I'm making mistakes in the design of the app structure. If so, I am asking for clarification.

Upvotes: 3

Views: 4076

Answers (3)

Hareesh
Hareesh

Reputation: 6900

Because you are saving the ids inside user try this way.

wares: Observable<any[]>; 

//inside ngOnInit or function
this.wares = this.db.list('users/currentUserId/wares').snapshotChanges().map(changes => {
  return changes.map(c => {
      const id = c.payload.key; //gets ids under users/wares/ids..
      let wares=[];
      //now get the wares
      this.db.list('warehouse/wares', ref => ref.orderByChild('id').equalTo(id)).valueChanges().subscribe(res=>{
        res.forEach(data=>{
            wares.push(data);
        })
      });
    return wares;
  });
});

Upvotes: 2

Tushar Acharekar
Tushar Acharekar

Reputation: 900

Yes , you can get exactly data that you want in firebase,

See official Firebase documents about filtering

You need to get each waresID

        var waresID = // logic to get waresID 
        var userId  = // logic to get userId
        var ref = firebase.database().ref("wares/" + userId).child(waresID);
        ref.once("value")
            .then(function(snapshot) {
               console.log(snapshot.val());
            });

this will return only data related to that waresID or userId

Note: this is javascript code, i hope this will work for you.

Upvotes: 1

DoesData
DoesData

Reputation: 7047

There are two things you can do. I don't believe Firebase allows you to query for multiple equals values at once. You can however loop over the array of "ids" and query for each one directly.

I am assuming you already queried for "waresIds" and you've stored those ID's in an array named idArray:

for id in idArray {
    database.ref('warehouse/wares').orderByChild('id').equalTo(id).once('value').then((snapshot) => {
        console.log(snapshot.val());
    }) 
}

In order to use the above query efficiently you'll have to index your data on id.

Your second option would be to use .childChanged to get only the updated data after your initial fetch. This should cut down drastically on the amount of data you need to download.

Upvotes: 2

Related Questions