Use case:
Users can upload images using UI (mobile, web). Firebase storage and insertion of database record for the file is done in UI. Users can upload a set number of files say for testing max 5. Solution is achieved through Firebase Storage to store files and Firebase Database to track the URLs of the image for future use in other screens.
I have a google cloud function that gets triggered when a user uploads an image in frontend to firebase storage. Once the file is uploaded I create a firebase database record under the uid. the google cloud function triggers onCreate()
.
Structure of Database
Users/{uid}/images/
{ name: file1.jpg, date_created: "2017-11-01", downloadURL : "//...."}
For every record creation I check the count of records under uid/images
node and check if the snapshot is greater than MAX_LIMIT
. If it is greater than MAX_LIMIT
I attempt to remove the record from the database and in another GCF (listening to .onDelete()
Trigger) I delete the firebase storage file.
The issue is Once the record count gets more than MAX_LIMIT
... the snapshot behaves strange. It iteratively deletes all the records thus triggering GCF Delete function and removing all files from storage.
No issues with GCF delete function for storage.. it works charm... and removes all files from storage due to the code behavior in GCF onCreate DB function.
To keep short putting below just the function that is logic trouble.
//var database = admin.database(); passed to function
exports.handler = function(event, database, esClient)
{
var usersRef = database.ref('users');
console.log('inside Backend Function1 -
checkImageCounterFunction');
console.log( 'event data =' + JSON.stringify(event.data.val()) );
console.log('event data length =' + event.data.numChildren());
console.log('event.params.uid =' + event.params.uid );
var objLength = 0;
usersRef.child(event.params.uid+'/images').once('value',
function(snapshot) {
console.log('Count: ' + snapshot.numChildren());
objLength = snapshot.numChildren();
console.log('database ref length =' + objLength);
if(objLength > 0) {
if(objLength > serverConfig.max_image_counter){
console.log('Maximum number of images upload found.
Deleting old images and records.');
var readDBPromise = new Promise(function (resolve, reject)
{
usersRef.child(event.params.uid+'/images')
.orderByChild('date_created')
.limitToFirst(objLength - serverConfig.max_image_counter)
.on("value", function(snapshot) {
console.log('snapshot.val()
=>'+JSON.stringify(snapshot.val()) );
snapshot.forEach(function(data) {
console.log('snapshot.for.data value
='+JSON.stringify(data) );
console.log('item Key = ' + data.key + ' val ='+
JSON.stringify(data.val()));
usersRef.child(event.params.uid+'/images/'+data.key)
.remove(function (error) {
if (!error)
console.log('Success - Firebase Database remove
{'+data.val().name+'}');
else
console.log('Error - Firebase Database remove
{'+data.val().name+'}');
});
});
resolve();
});
});
readDBPromise.then(function (result){
console.log('Returning from function!');
usersRef.child(event.params.uid+'/image_counter')
.set(serverConfig.max_image_counter);
return;
});
} //end if objLength > MAX
else
return usersRef.child(event.params.uid+'/image_counter')
.set(objLength);
}
else
console.log('objLength is 0 or negative = '+objLength);
return;
});
//return;
};
on()
to attach a listener in this line:.on("value", function(snapshot) {
. Isn'tonce()
what you need? It looks like later in the code youremove()
sub-values from the location, which will cause the listener to fire multiple times. – Bob Snyder