0

In my angular 4 application I use the push() method to append data to a list of data in Firebase Realtime Database. See Firebase documentation: https://firebase.google.com/docs/database/web/lists-of-data

The push() method generates a unique key every time a new child is added to the specified Firebase reference. This is an Array 'market' that consists of 250 objects with the keys symbol, price, balance:

market = [
  { symbol: '1ST', price_usd: 1, balance: 100},
  { symbol: '2ND', price_usd: 2, balance: 300},
  { symbol: '3RD', price_usd: 3, balance: 400}
  // etc etc for a total of 250 objects
];

I have written the following code in my Angular 4 component:

import {AngularFireDatabase} from 'angularfire2/database';
import * as firebase from 'firebase';

constructor(private db: AngularFireDatabase) {}

storeTicker() {
  const timestamp = firebase.database.ServerValue.TIMESTAMP;
  for (let object of market) {
    const path = object['symbol'];
    const itemsRef = this.db.list('Tickers/' + path);
    itemsRef.push({ symbol: path, price_usd: object['price_usd'], balance: object['balance'], time: timestamp});
  }
}

The code is executed when a button is clicked, this will result in a time-series for each reference.

My Firebase Realtime Database looks like this:

{ "Tickers" : {
    "1ST" : {
      "-Kx8gN5uZALd5BP2GCH6" : {
        "balance" : 0,
        "price_usd" : 0.25583,
        "symbol" : "1ST",
        "time" : 1508769890908
       }},
    "2ND" : {
      "-Kx8Z0xCl7ONZERk1ICo" : {
        "balance" : 0,
        "price_usd" : 0.0253829,
        "symbol" : "2ND",
        "time" : 1508769890908
      }},
    "3RD" : {
      "-Kx8gN5FEZEPsOe8S-Tw" : {
        "balance" : 0,
        "price_usd" : 0.767354,
        "symbol" : "3RD",
        "time" : 1508769890908
    }},
  // for a  total of 250 paths
}}

Each call to push() in this way will result in a roundtrip to Firebase. The problem is that Firebase only does push() for the first 100 references.

I can't find a limit on the number of roundtrips in the Firebase documentation: https://firebase.google.com/docs/database/usage/limits

I found one question on Stackoverflow Adding list of data in Firebase with a similar problem but I don't understand the update part.

My 2 questions are:

  1. Is there a maximum number of roundtrips in Firebase or is there some other error?

  2. How can I make my code work, by combining it into a multi-location update?

Grimthorr
  • 6,856
  • 5
  • 41
  • 53
Ian vh
  • 3
  • 4
  • I'm not sure I understand the problem. Doesn't the code work? – Frank van Puffelen Nov 20 '17 at 16:11
  • The code works, but Firebase stops at object nr 100: it only stores the first 100 of my 250 Array objects. I only found out this problem recently, my array used to be 50 objects. – Ian vh Nov 20 '17 at 18:11
  • 1
    Hmm... that sounds surprising. Can you reproduce that in a jsbin, so I can have a look? – Frank van Puffelen Nov 20 '17 at 19:54
  • I am quite new to Angular4 but I tried to reproduce it in Plunker: https://plnkr.co/edit/cPxdNsvEl25ipyhbGJJj?p=preview The plunker does not load, I dont understand completely all the Angular config part, but at least my code is there, maybe this helps to have a look? – Ian vh Nov 21 '17 at 15:14

1 Answers1

1

Using the push() method with no arguments will generate a unique ID locally and not result in a network operation to the database:

If you provide a value to push(), the value will be written to the generated location. If you don't pass a value, nothing will be written to the Database and the child will remain empty (but you can use the Reference elsewhere).

So, you could use this to obtain a unique ID for each item you need to push to the database, store this in an array and then use update() to send all items to the database simultaneously in a multi-location update, something like:

storeTicker() {
  const timestamp = firebase.database.ServerValue.TIMESTAMP;
  var updates = {};
  for (let object of market) {
    const key = this.db.list('/Tickers').push().key; // Get a new unique key (locally, no network activity)
    const path = object['symbol'] + '/' + key;
    updates[path] = {symbol: object['symbol'], price_usd: object['price_usd'], balance: object['balance'], time: timestamp};
  }
  this.db.object('/Tickers').update(updates);
}

The update() method (similar to the official Firebase JavaScript SDK update() method) works by sending the entire array to the specified location:

The values argument contains multiple property-value pairs that will be written to the Database together. Each child property can either be a simple property (for example, "name") or a relative path (for example, "name/first") from the current location to the data to update.

For a documentation example of this, see updating data using AngularFire or update specific fields using the JavaScript SDK.

Grimthorr
  • 6,856
  • 5
  • 41
  • 53
  • I get a failed to compile in the CLI: "Supplied parameters do not match any signature of call target" at the last part tickersRef.update(updates); – Ian vh Nov 22 '17 at 09:03
  • @Ianvh Ah sorry the `tickersRef` variable should be `this.db.object('/Tickers')` instead (as per [angularfire2 Multi-path update](https://github.com/angular/angularfire2/issues/435)), see my edit. – Grimthorr Nov 22 '17 at 09:48
  • It gives an error on the line for generating the unique key: "Property 'push' does not exist on type AngularFireObject<{}>". when I change the const key manually to a string like 'test' for example the code runs and generates an object of objects but the data is not stored in the database. Is this beacause tickersRef is an AngularFireDatabase service? – Ian vh Nov 22 '17 at 13:58
  • @Ianvh Ok, you could probably remove the `tickersRef` variable altogether. It seems that AngularFire behaves differently to the official [Firebase JavaScript SDK](https://firebase.google.com/docs/web/setup) which is confusing. The [AngularFire `update()` method](https://github.com/angular/angularfire2/blob/master/docs/rtdb/objects.md#updating-data) should work the same though. I've updated my answer again. – Grimthorr Nov 22 '17 at 14:35
  • One issue less, the unique key can be generated with `const key = this.db.createPushId()`. But the last line still doesn't update the database. I tried a callback like this [link](https://stackoverflow.com/questions/33610616/firebase-update-callback-to-detect-error-and-sucssess) to detect errors but that does not work either. Any thoughts on how to debug or find out the error by the browser developer tools? – Ian vh Nov 23 '17 at 18:24
  • There was an undefined variable in my market array, this togenther with the answer of @Grimthorr fixed the problem – Ian vh Nov 26 '17 at 09:49