Firebase infinite loop insert my item on child_added/set - firebase

I got an infinite loop inserting an item to my Firebase, so when I click on my post form, it inserts my item until I kill the process. Can you help me how to solve it?
PS : I'm using VueJS
var usersRef = new Firebase('https://xxxxxxxxxxxxxxxxxx.firebaseio.com/userslist/');
var vm = new Vue({
el: '#list1',
data: function () {
return{
// Initialisation du tableau de users
users: [],
sortKey: 'id',
reverse: 1,
nextKey: null
};
},
ready: function () {
// this works
//this.sortKey = 'name';
},
methods: {
updateUsers: function () {
},
removeUser: function (item) {
usersRef.child(item.id).remove();
},
addItem: function (e) {
e.preventDefault();
// get form data as Json
var jsonData = ConvertFormToJSON('form_add');
//console.log(jsonData);//test ok
//get the last item id and save it to next key
usersRef.limitToLast(1).on('child_added', function (snapshot) {
var lastKey = parseInt(snapshot.key());
this.nextKey = lastKey + 1;
console.log('nextKey ' + nextKey);//test ok
//
// save data to firebase
usersRef.child(this.nextKey).set(jsonData, function (snap) {
//console.log('add success');//test
//Notification par Jquery
var itemAdded = snap.val();
$.notify(itemAdded.firstname + " " + itemAdded.name + " à été ajouté", "success", {position: "top right"});
this.pendingKey = 0;
});
});
},
// Tri des colonnes
sortBy: function (_sortKey) {
this.reverse = (this.reverse == -1) ? 1 : -1;
this.sortKey = _sortKey;
console.log("SortKey " + this.sortKey);
}
}
});
usersRef.on('child_added', function (snapshot) {
var item = snapshot.val();
item.id = snapshot.key();
console.log('id ' + item.id);
vm.users.push(item);
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
thanks for your help

OK I've found a solution :
//get the last item id and save it to next key
var _nextKey = this.nextKey;
usersRef.limitToLast(1).on('child_added', function (snapshot) {
var lastKey = parseInt(snapshot.key());
_nextKey = lastKey + 1;
});
this.nextKey = _nextKey;
console.log('nextKey ' + this.nextKey);//test ok
// save data to firebase
usersRef.child(this.nextKey).set(jsonData, function (snap) {
//console.log('add success');//test
//Notification par Jquery
var itemAdded = snap.val();
$.notify(itemAdded.firstname + " " + itemAdded.name + " à été ajouté", "success", {position: "top right"});
});
May it help someone!

Related

How to pass variable key value in dynamodb

Am trying to get the items from DynamoDB table based on the current date. Using the date value in string format when am trying to run the below piece of code, its error out saying:
{
"errorMessage": "ERROR: Dynamo failed: TypeError: Cannot read property 'datatype' of undefined"
}
Below is the piece of code:
exports.handler = function(event, context) {
console.log("Request received:\n", JSON.stringify(event));
console.log("Context received:\n", JSON.stringify(context));
var doc = require('dynamodb-doc');
var dynamodb = new doc.DynamoDB();
var params = {
Key: {
"abc" : datetime1
},
TableName: 'myTable',
ProjectionExpression: 'message'
};
var Message = callback();
var datetiem = new Date().toISOString().split('T')[0];
console.log('date is ', datetiem); // prints 2018-01-09
var datetime1 = JSON.stringify(datetiem);
console.log(datetime1); //prints "2018-01-09"
function callback (message) {
dynamodb.getItem(params, function (err, data) {
if (err) {
context.fail('ERROR: Dynamo failed: ' + err);
} else {
console.log('Dynamo Success: ' + JSON.stringify(data, null, ' '));
console.log('data', data)
let Message = data['Item'].message;
console.log('test',Message);
}
});
}
};
It runs fine if I pass the value directly i.e. "abc" : "2018-01-09"
Can someone please advice?
I'm not sure your datetime1 variable is defined when you use it in parameters. Try this:
exports.handler = function(event, context) {
console.log("Request received:\n", JSON.stringify(event));
console.log("Context received:\n", JSON.stringify(context));
var doc = require('dynamodb-doc');
var dynamodb = new doc.DynamoDB();
var Message = callback();
var datetiem = new Date().toISOString().split('T')[0];
console.log('date is ', datetiem); // prints 2018-01-09
var datetime1 = JSON.stringify(datetiem);
console.log(datetime1); //prints "2018-01-09"
var params = {
Key: {
"abc" : datetime1
},
TableName: 'myTable',
ProjectionExpression: 'message'
};
function callback (message) {
dynamodb.getItem(params, function (err, data) {
if (err) {
context.fail('ERROR: Dynamo failed: ' + err);
} else {
console.log('Dynamo Success: ' + JSON.stringify(data, null, ' '));
console.log('data', data)
let Message = data['Item'].message;
console.log('test',Message);
}
});
}
};

Firebase https cloud function to send notifications always ends in timeout

Function execution took 60002 ms, finished with status: 'timeout'
I have cloud function that collects users product & price data, hits an external API to get the latest prices and sends a notification if the price has changed. I've read several similar questions like this but I am in fact sending a response back to the client. I've tried increasing the timeout to 120 seconds, but it still times out. So, I think there might be an issue with how I'm returning promises? Any suggestions?
Here is my code:
exports.pushTestWithRP = functions.https.onRequest((req, res) => {
var uidsAndTokens = [];
ref.child('tokens').once('value').then(snap => {
snap.forEach(childSnap => {
uidsAndTokens.push({
uid: childSnap.key,
deviceToken: childSnap.val()
});
});
return uidsAndTokens;
}).then((uidsAndTokens) => {
var uidsAndCruises = [];
ref.child('watchlist-items/users').once('value').then(snap => {
snap.forEach(childSnap => {
var uid = childSnap.key;
childSnap.forEach(childChildSnap => {
var product = childChildSnap.key;
var productWatchInfo = childChildSnap.val();
uidsAndProducts.push({
uid: uid,
product: product,
watchInfo: productWatchInfo
});
}); // end childChildSnap
}); // end childSnap
return uidsAndProducts;
}).then((uidsAndProducts) => { // end snap watchlist-items/users
var uidsOnly = [];
for (var i=0; i<uidsAndTokens.length; i++) {
uidsOnly.push(uidsAndTokens[i].uid);
}
// user has a FCM token
var uidsAndProductsWithTokens = [];
for (var i=0; i<uidsAndProducts.length; i++) {
//check if exists in tokens array
var currUid = uidsAndProducts[i].uid;
if (uidsOnly.includes(currUid)) {
//console.log('this uid has a token: ', currUid);
uidsAndProductsWithTokens.push(uidsAndProducts[i]);
} else {
//this uid does NOT have a token
}
}
function getTokenForUid(uid) {
for (var i in uidsAndTokens) {
if (uidsAndTokens[i].uid == uid) {
var deviceToken = uidsAndTokens[i].deviceToken;
break;
}
}
return deviceToken;
}
var allPromises = [];
// call API only for uids with tokens
for (var i=0; i<uidsAndProductsWithTokens.length; i++) {
const product = uidsAndProductsWithTokens[i].product;
const uid = uidsAndProductsWithTokens[i].uid;
const deviceToken = getTokenForUid(uid);
const pDates = uidsAndProductsWithTokens[i].watchInfo.pDates;
const pName = uidsAndProductsWithTokens[i].watchInfo.pName;
getCurrentPricesFromAPI(product).then((response) => {
if (typeof response.response != 'undefined') {
const productId = response.response.product.product_id;
const allPrices = response.response.prices;
const promises = [];
// parse thru prices and send notifications
for (var date in pDates) {
// get all current prices and sort by price to get cheapest
var cheapest = [];
for (var i = 0; i < allPrices.length; i++) {
if (allPrices[i].data[productId][date] && allPrices[i].data[productId][date].hasOwnProperty('Inside')) {
const iPrice = allPrices[i].data[productId][date].Inside;
cheapest.push(iPrice);
}
}
if (cheapest[0] > 0) {
cheapest = cheapest.sort(function (a, b) { return a - b; });
if (sDates[date].hasOwnProperty('Inside')) {
const priceDiff = cheapest[0] - sDates[date].Inside.price;
if (priceDiff < -10) {
const payload = {
notification: {
title: pName + ' Price DROP Alert!',
body: 'prices for the ' + date + ' are $' + cheapest[0] + ' (DOWN $' + Math.abs(priceDiff) + ')',
sound: 'default'
}
};
promises.push(admin.messaging().sendToDevice(deviceToken, payload));
}
else if (priceDiff > 10) {
const payload = {
notification: {
title: pName + ' Price Hike Alert',
body: 'prices for the ' + date + ' are $' + cheapest[0] + ' (UP $' + priceDiff + ')',
sound: 'default'
}
};
promises.push(admin.messaging().sendToDevice(deviceToken, payload));
}
}
}
}
allPromises = allPromises.concat(promises);
}
}) // end handle API response
} // end for loop
return allPromises;
}).then((allPromises) => {
return Promise.all(allPromises);
res.send('got tokens and ids');
}).catch(error => {
res.send('there was an error');
});
}); // end uidsAndTokens
}); // end function
I can't figure this out and would appreciate any help!

Firebase Cloud Functions - return undefined

This is the code that I am using to fetch the senderName and messageText from my database. In my logs, I am getting an error saying "Function returned undefined, expected Promise or value". I am using this function to send notifications to the recevier of the message. The notification is being sent appropriately.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendPushNotification = functions.database.ref('/messages/{messageId}').onWrite(event => {
var db = admin.database();
var messageText;
var senderName;
var receiverId;
var senderId;
var messageId = event.params.messageId;
var messageTextRef = db.ref('/messages/' + messageId + '/text');
var senderIdRef = db.ref('/messages/' + messageId + '/fromId');
var receiverIdRef = db.ref('/messages/' + messageId + '/toId');
messageTextRef.once("value", function(data) {
messageText = data.val();
senderIdRef.once("value", function(data) {
senderId = data.val();
receiverIdRef.once("value", function(data) {
receiverId = data.val();
var senderNameRef = db.ref('/users/' + senderId + '/name');
senderNameRef.once("value", function(data) {
senderName = data.val();
console.log(senderName);
console.log(messageText);
const payload = {
notification : {
title: String(senderName),
body: String(messageText),
badge: "1",
sound: 'default',
}
};
return admin.database().ref('fcmToken').once('value').then(allToken => {
if (allToken.val()) {
const token = Object.keys(allToken.val());
return admin.messaging().sendToTopic(receiverId, payload).then(response => {
});
};
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
});
});
You have a monster function there. If you return the outermost Promise when you are getting all the database values that should fix the issue, and also ensure that your function is not stopped before all computation is complete. In your case this is on line ~25:
...
return messageTextRef.once("value", function(data) {
...

Firebase $remove() confused about using ref.key() or $id

I am building a very simple edit/delete function for a list of posts and got the update function working with:
$scope.update = function() {
var fb = new Firebase("https://mydb.firebaseio.com/Posts/" + $scope.postToUpdate.$id);
var article = $firebaseObject(fb);
article.Title = $scope.postToUpdate.Title;
article.Intro = $scope.postToUpdate.Intro;
article.Body = $scope.postToUpdate.Body;
article.$save().then(function(ref) {
console.log($scope.postToUpdate.Title);
}, function(error) {
console.log("Error:", error);
});
}
I assumed that the delete function would be almost identical i.e.
$scope.deletePost = function() {
var fb = new Firebase("https://mydb.firebaseio.com/Posts/" + $scope.postToDelete.$id);
var article = $firebaseObject(fb);
$scope.postToDelete = article;
article.$remove().then(function(ref) {
console.log("removed:" + $scope.postToDelete.Title);
}, function(error) {
console.log("Error:", error);
});
}
button: <button type="button" ng-click="deletePost()">Delete</button>
But nothing happens. I tried the verion with the firebase ref_key instead but this still has not worked
$scope.deletePost = function() {
var fb = new Firebase("https://mydb.firebaseio.com/Posts/" + id);
var id = ref.key();
var article = $firebaseObject(fb);
$scope.postToDelete = article;
article.$remove.then(function(ref) {
console.log("removed:" + $scope.postToDelete.Title);
}, function(error) {
console.log("Error:", error);
});
}
I have been reading through some of the threads and wondering if article should be an array in order to delete the entire object? How do I target the specific item in order to delete it?
FIXED WITH: article.$remove(article).then(function(ref) But I still do not understand when to use ref.key() or $id (firebase/angularfire?)

Can't wait without a fiber

I'm using the node-imap meteor package to retrieve an email, then use that email to find a guest in a Guests collection. I get the "can't wait without a fiber error" when I include the Guest.findOne code. Here's the code
function openInbox(cb) {
imap.openBox('INBOX', true, cb);
}
imap.once('ready', function() {
openInbox(function(err, box) {
if (err) throw err;
var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM SUBJECT DATE)','TEXT'] });
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] found, %d total bytes', (info.which), info.size);
var buffer = '', count = 0;
stream.on('data', function(chunk) {
count += chunk.length;
buffer += chunk.toString('utf8');
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] (%d/%d)', (info.which), count, info.size);
});
stream.once('end', function() {
if (info.which !== 'TEXT') {
console.log(prefix + 'Parsed header: ');
var header = Imap.parseHeader(buffer);
var from = header.from;
email = from[0].slice(from[0].indexOf('<')+1, from[0].indexOf('>'));
fetched = true;
}
else
console.log(prefix + 'Body [%s] Finished', (info.which));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', (attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
imap.end();
if(fetched){
var guest = Guests.findOne({email: email}, {reactive: false}); // <-- this code causes the error
if(guest){
console.log(guest)
}
}
});
});
});
imap.once('error', function(err) {
console.log(err);
});
imap.once('end', function() {
console.log('Connection ended');
});
imap.connect();
So I tried to do a Meteor.bindEnvironment based on Future.wait() can't wait without a fiber (while waiting on another future in Meteor.method)
function openInbox(cb) {
imap.openBox('INBOX', true, Meteor.bindEnvironment(cb));
}
And get the error message "Cannot read property '_meteor_dynamics' of undefined". So there is no Fiber to bind to? I am still fairly new to Meteor so don't really know where to go from here. An explanation on what is going on and a solution would be great. Any help is appreciated.

Resources