Reputation: 5177
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.
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
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