Cloud Functions for Firebase - what is wrong with my code? - firebase

The following code executed when something is written at a certain location in the database.
What I expect from this code : If the number of coins are => 500 to subtract only once 500 coins from the current coins value and to add one ticket to the existing ticket value.
What I am getting in reality: The code recursively subtracts 500 coins until the coin value is lower than 500; It adds more tickets then it should.
Please , can somebody modify my code to work as expected ?
I do not know what I am doing wrong
exports.TransformCoinsIntoTickets1 = functions.database.ref('/AddTickets/{userid}').onWrite(event => {
var user = event.params.userid;
/// first get coins to see if we can lower coin value
var usercoinRef1 = admin.database().ref('coins').child(user);
usercoinRef1.on("value", function(snapshot) {
var numberofcoins = snapshot.val();
console.log("We are in snapshot of coins -> He has coins = " + numberofcoins);
if (numberofcoins >= 500 )
return usercoinRef1.set(numberofcoins-500).then(() => {
var ticketRef1 = admin.database().ref('tickets').child(user);
ticketRef1.on("value", function(snap123) {
var numberoftickets = snap123.val();
return ticketRef1.set(numberoftickets+1).then(() => {
console.log('Tickets Write succeeded!');
});
}, function (error) {
console.log("Error Tickets: " + error.code);
});
console.log('Coins Write succeeded!');
});
}, function (error) {
console.log("Error Coins: " + error.code);
});
//then we write the new coin value if we need to
});

I just realized that instead of
on
i should use
once
So, replacing
.on("value",
with
.once("value",
resolved the problem.

Related

Firebase/Firestore no matching index found but no option to create one

I'm trying to run a firestore query in my app which is is throwing up an error that an index is missing.
Firestore always used to also include a link to click for the console to create the missing index, but it's not there this time so I'm stuck!
Not sure what I've done differently this time.
This is the console error:
prebuilt-d16b955d-cdb9e87f.js:188 Uncaught (in promise) FirebaseError: no matching index found.
at new e (prebuilt-d16b955d-cdb9e87f.js:188)
at prebuilt-d16b955d-cdb9e87f.js:10416
at prebuilt-d16b955d-cdb9e87f.js:10414
at e.onMessage (prebuilt-d16b955d-cdb9e87f.js:10403)
at prebuilt-d16b955d-cdb9e87f.js:10356
at prebuilt-d16b955d-cdb9e87f.js:10387
at prebuilt-d16b955d-cdb9e87f.js:15180
This is my JS function:
loadcatalogues() {
console.log(this.clubID);
this.showspinner = true;
this.catalogues = [];
var today = moment().utc().unix();
let self = this;
fb.catalogueCollection
.where("clubID", "==", this.clubID)
.where("expiry", ">", today)
.orderBy("expiry", "asc")
.orderBy("price", "asc")
.get()
.then(function (querySnapshot) {
querySnapshot.forEach(function (doc) {
if (
doc.data().members &&
doc.data().members.indexOf(self.userProfile.id) !== -1
) {
return false;
}
var starttime = moment.unix(doc.data().start).utc();
var endtime = moment.unix(doc.data().expiry).utc();
var tempdata = {
title: doc.data().title,
description: doc.data().description,
start: starttime.format("DD-MM-YYYY"),
expiry: endtime.format("DD-MM-YYYY"),
price: doc.data().price,
purchased: false,
stripeid: doc.data().stripeid,
catalogueid: doc.id,
limited: doc.data().limited,
};
self.catalogues.push(tempdata);
});
if (self.catalogues.length == 0) {
self.shownooptions = true;
}
self.showspinner = false;
});
},
If I remove the first where clause (.where("clubID", "==", this.clubID)) then the query runs fine, so I'm guessing an index already exists for that query.
I've only recently added the clubID field, so could that be missing an index?
Thanks!!
Looks like there's currently a problem with Google firestore.
Raised a support call and they have confirmed they have received several other reports of this and their engineering team are investigating.

How to get a data from firestore while using batch?

I want to perform a batch transaction in firestore. I am storing last key in other collection.
i need to get the last key then increase by 1, then create two documents using this key. How can i do this?
let lastDealKeyRef = this.db.collection('counters').doc('dealCounter')
let dealsRef = this.db.collection('deals').doc(id)
let lastDealKey = batch.get(lastDealKeyRef) // here is the problem..
batch.set(dealsRef, dealData)
let contentRef = this.db.collection('contents').doc('deal' + id)
batch.set(contentRef, {'html': '<p>Hello World</p>' + lastDealKey })
batch.commit().then(function () {
console.log('done') })
If you want to read/write data in a single operation you should be using a transaction.
// Set up all references
let lastDealKeyRef = this.db.collection('counters').doc('dealCounter');
let dealsRef = this.db.collection('deals').doc(id);
let contentRef = this.db.collection('contents').doc('deal' + id);
// Begin a transaction
db.runTransaction(function(transaction) {
// Get the data you want to read
return transaction.get(lastDealKeyRef).then(function(lastDealDoc) {
let lastDealData = lastDealDoc.data();
// Set all data
let setDeals = transaction.set(dealsRef, dealData);
let setContent = transaction.set(contentRef, {'html': '<p>Hello World</p>' + lastDealKey });
// Return a promise
return Promise.all([setDeals, setContent]);
});
}).then(function() {
console.log("Transaction success.");
}).catch(function(err) {
console.error("Transaction failure: " + err);
});
You can read more about transactions and batches here:
https://firebase.google.com/docs/firestore/manage-data/transactions

async.parallel stops working on huge list of array

i'm still new with async module. Basically, I want to do the batch update operation from array using async.parallel, like this :
var _ = require('lodash');
var async = require('async');
var list = req.body.dataArr; //the array
var asyncTasks = [];
_.each(hotelList,function(value,key){
asyncTasks.push(function(callback){
Hotel.find({hotelId:value.hotelId}).exec(function(err,hotels){
if(err){
console.log(err);
}
if(hotels.length ==0){
//hotel not found
console.log('Hotel not found for ID :'+value.hotelId);
return;
}
hotels[0].countryCode = value.countryCode;
hotels[0].city = value.city;
hotels[0].save(function(err){
if(err){
console.log('saving failed ... Reason : '+err);
return;
}
console.log('saving successful');
});
});
});
});
async.parallelLimit(asyncTasks,function(){
//async.parallelLimit(asyncTasks,10, function(){
console.log('finish call asyncTask');
res.json({status:'success'});
});
The problem is, when i run it using all data in array (there's more then 100.000 indexes), it only stop without any message eventough i have waited for several minutes, but when i try to limit the array to only 10 using parallelLimit, it only do 10 update operation like this :
saving successful
Is there something wrong in how I'm using async? Sorry if my english is bad.
Your asyncTasks functions need to call their callback parameters when they've finished their work so that parallel or parallelLimit knows when they're done.
_.each(hotelList,function(value,key){
asyncTasks.push(function(callback){
Hotel.find({hotelId:value.hotelId}).exec(function(err,hotels){
if(err){
console.log(err);
return callback(err);
}
if(hotels.length ==0){
//hotel not found
console.log('Hotel not found for ID :'+value.hotelId);
return callback(Error('Not found'));
}
hotels[0].countryCode = value.countryCode;
hotels[0].city = value.city;
hotels[0].save(function(err){
if(err){
console.log('saving failed ... Reason : '+err);
return callback(err);
}
console.log('saving successful');
callback();
});
});
});
});

$firebaseArray $indexFor() not finding key when given value

I have this firebase:
users: {
userId: {
notifications: {
notificationId: "Notification"
}
}
}
When given "Notification", I'm trying to find its notificationId (which is generated from the push() method) so I can eventually delete it. According to the docs, the $indexFor() method should do this for me. Here's my code:
var ref = new Firebase('https://url.firebaseio.com/');
$scope.dismissNotification = function(notification) {
var notificationRef = ref.child('users/' + $scope.currentUser.id + '/notifications');
var notifications = $firebaseArray(notificationRef);
notifications.$loaded().then(function(data) {
console.log(data);
console.log(data.$indexFor(notification));
}).catch(function(error) {
console.log('Error: ' + error);
});
};
The first log is the correct object with the notification string inside that I'm looking for, but the second log returns -1, when I want it to return the notificationId associated with it.
Not sure what you're trying to accomplish, but this is the simplest way to find the key for a given value:
var notificationRef = ref.child('users/' + $scope.currentUser.id + '/notifications');
var query = notificationRef.orderByValue().equalTo(notification);
query.once('child_added', function(snapshot) {
console.log(snapshot.key());
});

Meteor Reactive Session: Not Working (Why?)

I'm having trouble with reactive Sessions in Meteor.js.
Demo: Meteor Pad
Template.rows.helpers({
'rows': function () {
return Session.get('rows'); // data set in Session
}
});
Template.count.events({
'click .mdl-radio__button': function (e) {
// target represents a number of selected rows (1, 2, 5, or 10)
var value = $(e.currentTarget).val();
Session.set('limit', value);
},
'click #reset': function () {
Session.set('limit', 0);
Session.set('rows', null);
},
'click #run': function () {
// should only get rows when run() is pressed
Session.set('rows', currentItems);
}
});
Users should be able to select a new number of collections to receive, controlled by the limit. However, I keep getting the following error:
Error: Match error: Failed Match.OneOf or Match.Optional validation
Any ideas why? Can someone show me a working MeteorPad demo?
I'm having trouble with your meteorpad. But your problem isn't Session. The problem is your usage of Tracker.autorun. You should read the docs on that.
You are assuming that Tracker.autorun(getItems) returns what getItems returns. That's not the case tough. You'll need to set currentItems inside the autorun (in your case getItems).
getItems = function () {
if (Session.get('limit') > 0) {
currentItems = Items
.find({}, {limit: Session.get('limit')})
.map(function (item, index) {
item.index = index + 1;
return item;
});
} else {
currentItems = null;
}
};
Finally figured it out. Apparently Session creates a string, so that Session.set('limit', 1) sets the limit to "1". Of course, strings can be processed in a Mongo collection request.
The solution was using {limit: parseInt(Session.get('limit')}.

Resources