Hussain
Hussain

Reputation: 5177

How to insert to existing Firebase DB array using Firebase Functions in javascript

I am trying to build an app that stores and shows book quotes by it's title and by it's author. I am using Firebase for the backend. My Firebase data structure looks like this.

enter image description here

When a book quote is added, I know the author. So to store the quote in author automatically, I am trying to use Firebase Functions.

I have tried two approaches,

Merge quotes from author with quotes from the book when book is updated.

exports.newQuotesTrigger = functions.database.ref('library/{bookAndAuthor}').onWrite((snap, context) => {
    const message = snap;
    console.log('Retrieved message content: ', message);

    const newValue = message.after.val();
    const oldValue = message.before.val();

    const author = snakeCase(newValue.author);
    admin.database().ref('authors/' + author).child('quotes').set(newValue.quotes);
    console.log('Updated author quotes');

    return message;
});

Just push the difference of new quotes and old quotes from the book

exports.newQuotesTrigger = functions.database.ref('library/{bookAndAuthor}').onWrite((snap, context) => {
    const message = snap;
    console.log('Retrieved message content: ', message);

    const newValue = message.after.val();
    const oldValue = message.before.val();

    const newQuotes = newValue.quotes || [];
    const oldQuotes = oldValue.quotes || [];
    const diff = arrayDiff(newQuotes, oldQuotes);

    if (diff) {
        console.log('Quotes were updated for ', {title: newValue.title, author: newValue.author});
        const author = snakeCase(newValue.author);
        admin.database().ref('authors/' + author).child('quotes').push(diff);
        console.log('Updated author quotes');
    }

    return message;
});

Both don't append/insert update quotes properly. I haven't found a way to append/insert to a Firebase db array.

Upvotes: 1

Views: 1300

Answers (1)

Renaud Tarnec
Renaud Tarnec

Reputation: 83093

You have to use update in order to "update specific children of a node without overwriting other child nodes", see:

https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields

Your first piece of code should work with update if you slightly change your structure as follow with autogenerated Ids for the quotes

Database

author
    - nassim
      - quoteID1: "...."  <- ID auto generated
      - quoteID2: "...."  <- ID auto generated
      - quoteID3: "...."  <- ID auto generated

Cloud Function

Replace, in your first version of the code, these lines

    admin.database().ref('authors/' + author).child('quotes').set(newValue.quotes);
    console.log('Updated author quotes');
    return message;

by those ones

  const quotesObject = newValue.quotes;
  var updates = {};      

  Object.keys(quotesObject).forEach(function (key) {
    let quote = quotesObject[key];
    const newQuoteKey = firebase.database().ref('authors/' + author).child('quotes').push().key;
    updates[newQuoteKey] = quote ;
  });

  return admin.database().ref('authors/' + author).child('quotes').update(updates);

Another important point is that you are not returning a promise in your Cloud Functions. You should return the promise from the update (or set) and not the message. See https://www.youtube.com/watch?v=652XeeKNHSk&t=26s


In case you really have to keep the quotes id generated by yourself (i.e. 0, 1, 2, etc) in a sequence you will have to manipulate arrays by getting the previous array of values, adding the new quote and overwriting the existing set of quotes with the new array.. a lot of efforts! especially that with auto-generated ids you will not loose the quotes order: they will still be saved in the order they were written.

Upvotes: 2

Related Questions