Reputation: 121
I've now spent the better part of 16 hours tearing my hair out over javascript, so I figured it was time to ask someone.
I have an android app made in android studio, which is connected to a firebase database that looks roughly like this:
nameOfDatabase
Places
Bar
B001
place_ID_ : "B001"
...
average_rating_ : 0
...
number_of_ratings_ : 0
...other bars
...other place types
Ratings
ratingID1
place_ID_ : "B001"
rating_ : 3
user_ID_ : 4315732985097
...other parameters
...other ratings
What I want to do is simply update the number_of_ratings_ and average_ratings_ for the place matching the place_ID_ whenever a rating_ changes, either by an existing value being modified or a new Rating being added. My index.js code for the firebase functions node module looks like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.UpdateAverageRatings = functions.database.ref('/Ratings/{rating_uid}/rating_').onWrite(event => {
let place_ID_ = admin.database().ref('Ratings/' + String(event.params.rating_uid) + '/place_ID_').val();
console.log(place_ID_);
let place_type_ = 'BARs';
let place_ID_ = 'B001';
let avg_rating_ = 0;
let accumulated_rating_ = 0;
let number_of_ratings_ = 0;
//Object.keys(place_ID_.parent).forEach(function(key) {
// if (place_ID_.parent[key] == 'place_ID_'){
// accumulated_rating_ += place_ID_.parent[key].value();
// number_of_ratings_ += 1;
//}});
let place_change_ = admin.database().ref('Places/' + String(place_type_) + '/' +String(place_ID_));
place_change_.child('average_rating_').set(avg_rating_);
place_change_.child('number_of_ratings_').set(number_of_ratings_);
return 0;
});
Setting the values, in the last two lines before return, works as it should, but for now I'm just setting the dummy values '0'. An idea for assigning the correct values is commented out for later use.
The problem is that whatever I try, I can't seem to read any values from the database, as seen attempted in the 'let place_ID_ ...' line and subsequent console log.
I've read through the documentation (https://firebase.google.com/docs/functions/database-events) and stackexchange posts countless times, but I either get
"TypeError: admin.database(...).ref(...).val is not a function"
in the firebase console logs , or if I remove val();
W {
u:
dh {
app:
FirebaseApp {
firebaseInternals_: [Object],
services_: [Object],
isDeleted_: false,
name_: '[DEFAULT]',
options_: [Object],
database: [Function: bound ],
INTERNAL: [Object] },
L:
Tb {
host: 'projectname.firebaseio.com',
domain: 'firebaseio.com',
Pc: true,
ne: 'projectname',
tg: false,
ef: '',
Za: 'projectname.firebaseio.com' },
Ua: Ff { qc: {} },
Sc: null,
ca: he { tb: [] },
td: 1,
Qa:
kh {
id: 0,
f: [Function],
nd: {},
'$': {},
pa: [],
Lc: 0,
Hc: [],
ma: false,
Ra: 1000,
qd: 300000,
Eb: [Function: bound ],
Gc: [Function: bound ],
se: [Function: bound ],
L: [Object],
xe: null,
Ab: null,
Ea: null,
mb: null,
Xc: [Object],
ae: false,
he: 0,
Rd: undefined,
sb: [Object],
Kb: true,
Ed: {},
kg: 0,
Oe: true,
je: null,
xc: null },
va:
kh {
id: 0,
f: [Function],
nd: {},
'$': {},
pa: [],
Lc: 0,
Hc: [],
ma: false,
Ra: 1000,
qd: 300000,
Eb: [Function: bound ],
Gc: [Function: bound ],
se: [Function: bound ],
L: [Object],
xe: null,
Ab: null,
Ea: null,
mb: null,
Xc: [Object],
ae: false,
he: 0,
Rd: undefined,
sb: [Object],
Kb: true,
Ed: {},
kg: 0,
Oe: true,
je: null,
xc: null },
qg: Df { qf: {}, Sc: [Object], va: [Object] },
jc: Vc { sd: '', Mc: null, A: [Object] },
fe: Nb { Hd: [Object] },
md: Dg { wa: [Object], hb: [Object], Be: {}, fc: {}, zc: [Object] },
ia: Eb { B: null, k: null },
Xa: ch { ta: [Circular], ba: [Object], INTERNAL: [Object] },
cd: 0,
ge: null,
K: Dg { wa: [Object], hb: [Object], Be: {}, fc: {}, zc: [Object] } },
path: G { o: [ 'Ratings', 'ratingID1', 'place_ID_' ], Y: 0 },
m:
jf {
xa: false,
ka: false,
Ib: false,
na: false,
Pb: false,
oa: 0,
kb: '',
bc: null,
xb: '',
Zb: null,
vb: '',
g: Ae {} },
Kc: false,
then: undefined,
catch: undefined }
, which is rather incredible given that this database key only holds an integer value.
Any help would be greatly appreciated, I can provide more information if necessary.
Edit I've now tried using the async/await keywords coupled with once('value).then(snapshot => snapshot.val()) to get the value, but this does not compile, or if I remove async/await, the promise never resolves.
Upvotes: 0
Views: 1429
Reputation: 66325
Retrieving a value from the database is async.
If you look at https://firebase.google.com/docs/database/web/read-and-write it has an example of retrieving a value once:
var userId = firebase.auth().currentUser.uid; return firebase.database().ref('/users/' + userId).once('value').then(function(snapshot) { var username = (snapshot.val() && snapshot.val().username) || 'Anonymous'; // ... });
You either use on('value')
for receiving updates to the value, or once('value')
for getting it once. Both return a promise which passes a snapshot
, and snapshot.val()
will give you the value at that node.
Thus you can retrieve the value like so:
const place_ID_ = await admin.database().ref(`Ratings/${event.params.rating_uid}/place_ID_`).once('value').then(snapshot => snapshot.val());
console.log('place_ID_:', place_ID_);
Psst, all those underscores are terribly ugly just saying, try camelCase ;) And you don't need to wrap variables in String()
if they're already strings, or you're concatenating with other strings. And you can use const
for variables which don't change rather than let
.
Upvotes: 2