when i want to update Cloud Firestore from Realtime Database i deployed bellow code and i get error.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const firestore = functions.firestore;
exports.onUserStatusChange = functions.database
.ref('/status/{userId}')
.onUpdate(event => {
var db = admin.firestore();
//const usersRef = firestore.document('/users/' + event.params.userId);
const usersRef = db.collection("users");
var snapShot = event.data;
return event.data.ref.once('value')
.then(statusSnap => snapShot.val())
.then(status => {
if (status === 'offline'){
usersRef
.doc(event.params.userId)
.set({
online: false,
last_active: Date.now()
}, {merge: true});
}
})
});
TypeError: Cannot read property 'ref' of undefined
at exports.onUserStatusChange.functions.database.ref.onUpdate.event (/user_code/index.js:18:20)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:733:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
It looks like you got the code for a beta version of Cloud Functions for Firebase. The syntax has changed in the 1.0 version. From the documentation on upgrading your Cloud Functions:
or onWrite and onUpdate events, the data parameter has before and after fields. Each of these is a DataSnapshot with the same methods available in admin.database.DataSnapshot. For example:
Before (<= v0.9.1)
exports.dbWrite = functions.database.ref('/path').onWrite((event) => {
const beforeData = event.data.previous.val(); // data before the write
const afterData = event.data.val(); // data after the write
});
Now (>= v1.0.0)
exports.dbWrite = functions.database.ref('/path').onWrite((change, context) => {
const beforeData = change.before.val(); // data before the write
const afterData = change.after.val(); // data after the write
});
So you will want to use:
.onUpdate((change, context) => { to declare the funtcion, instead of .onUpdate(event => {
use change.after to refer to the data, instead of event.data
use change.after.ref.once('value'), instead of event.data.ref.once('value')
Since it seems that this code is mostly copied from somewhere, I'd recommend getting an updated version from there. For example, the Firestore documentation that your code is likely based on, contains an up-to-date example here: https://firebase.google.com/docs/firestore/solutions/presence#updating_globally
Try to change below code, as firebase functions on events have two properties any more. So, ref position is:
.onUpdate((event,context) => {
....
return event.ref.once('value')
...
event.data does not exist anymore, instead event.val() for more info and event has properties like
Related
I am trying to log each time an account is created and deleted.
I created a trigger functions.auth.user().onCreate() and as I understand it returns an user object as in the docs: here, and here.
The functions deploy without trouble but when the trigger is called it throws an error:
Error: Process exited with code 16
at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:92:22)
at process.emit (events.js:314:20)
at process.EventEmitter.emit (domain.js:483:12)
at process.exit (internal/process/per_thread.js:168:15)
at sendCrashResponse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/logger.js:44:9)
at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:88:44)
at process.emit (events.js:314:20)
at process.EventEmitter.emit (domain.js:483:12)
at processPromiseRejections (internal/process/promises.js:209:33)
at processTicksAndRejections (internal/process/task_queues.js:98:32)
Error which I cannot understand.
Here is my code
// functions/index.js
const functions = require('firebase-functions')
const admin = require('firebase-admin')
const { google } = require('googleapis')
const { firestore } = require("firebase-admin");
exports.logging = require('./logging');
admin.initializeApp()
// And other working functions
The actual functions
// functions/logging.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { firestore } = require('firebase-admin');
const authUserTrigger = functions.auth.user()
exports.userSignup = authUserTrigger.onCreate((user) => {
storeUser(user)
})
exports.userDelete = authUserTrigger.onDelete((user) => {
storeUser(user)
})
async function storeUser(user) {
// functions.logger.log(user.email) -> this works
// Destructured original object
let updatedUser = (({ displayName, email }) => ({ displayName, email }))(user);
functions.logger.log('updatedUser', updatedUser )
await admin
.firestore()
.collection('logs')
.doc('users')
.collection('signup')
.set({
user: {updatedUser}, // I think this is the culprint
// user, This doesn't work either
createTimestamp: firestore.FieldValue.serverTimestamp()
}, { merge: true })
};
Thank you in advance
EDIT ==========
#Tanay was right. Needed to change set to add.
As #Tanay stated, you cannot use set() in a collection in Firebase, it must be a document. If you want to add a document to the collection with an auto ID then you can use add() on the collection with the data.
I have a table titled 'bestOffers' in Cloud Firestore
I am using a function that calls when a document is added to a table.
The event settings are like this:
Event type: create
The path to the document: bestOffers/{id}
Function:
And when I run the function, I get a cannot read property 'databaseURL' of null error
Can you please tell me what am I doing wrong?
Code:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp()
exports.sendNotification = functions.database.ref('bestOffers/{id}').onWrite(async (change, context) => {
})
Tracing:
TypeError: Cannot read property 'databaseURL' of null
at resourceGetter (/workspace/node_modules/firebase-functions/lib/providers/database.js:92:54)
at cloudFunctionNewSignature (/workspace/node_modules/firebase-functions/lib/cloud-functions.js:102:13)
at cloudFunction (/workspace/node_modules/firebase-functions/lib/cloud-functions.js:151:20)
at Promise.resolve.then (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:198:28)
at process._tickCallback (internal/process/next_tick.js:68:7)
Have a look at the signature of the handler function that is passed to onWrite. It has two parameters: a Change<DataSnapshot> and an EventContext.
You declare your Cloud Function with:
...onWrite(async () => {...});
You should do as follows:
.onWrite(async (change, context) => {
const beforeData = change.before.val(); // data before the write
const afterData = change.after.val(); // data after the write
});
and, then, use the change object to get the data stored at the node that triggered the Cloud Function.
I try to learn how to send a notifications using a firebase functions. So I'm using this example code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendAdminNotification = functions.database.ref('/message').onWrite(event => {
const news = event.data.val();
const payload = {notification: {
title: 'New news',
body: `${news.title}`
}
};
return admin.messaging().sendToTopic("News",payload)
.then(function(response){
return console.log('Notification sent successfully:',response);
})
.catch(function(error){
console.log('Notification sent failed:',error);
});
});
but it gives me an error:
Cannot read property 'val' of undefined
I've been looking for a solution, tried this, but still no-go...
Any suggestions would be greatly appreciated.
I think you are not using the syntax as specified in the documentation.
Refer this documentation.
Anyways, as I see in the documentation linked above, your code should be :
exports.sendAdminNotification = functions.database.ref('/message')
.onWrite((change, context) => {
console.log(change);
// Do something with change or context
});
Sorry if this seems like a really basic question, the concept of cloud functions is extremely new to me and i'm still highly in the learning process.
However, whilst trying to execute this cloud function i get the following error
TypeError: Cannot read property 'data' of undefined
Full log can be seen here
For reference as well, I didnt make this function, im just trying to get it working, i used this video.
The actual cloud function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const firestore = admin.firestore();
const settings = { timestampInSnapshots: true };
firestore.settings(settings);
const stripe = require('stripe')(functions.config().stripe.token);
exports.addStripeSource =
functions.firestore.document('cards/{userid}/tokens/{tokenid}')
.onCreate(async (tokenSnap, context) => {
var customer;
const data = tokenSnap.after.data();
if (data === null) {
return null
}
const token = data.tokenId;
const snapchat = await
firestore.collection('cards').doc(context.params.userId).get();
const customerId = snapshot.data().custId;
const customerEmail = snpashot.data().email;
if (customerId === 'new') {
customer = await stripe.customers.create({
email: customerEmail,
source: token
});
firestore.collection('cards').doc(context.params.userId).update({
custId: customer.id
});
}
else {
customer = await stripe.customers.retrieve(customerId)
}
const customerSource = customer.sources.data[0];
return firestore.collection('cards').doc(context.params.userId).collection('sources').doc(customerSource.card.fingerprint).set(customersource, { merge: true });})
The dart code im using for writing a payment service:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class PaymentService {
addCard(token) {
FirebaseAuth.instance.currentUser().then((user) {
print("Found User");
Firestore.instance
.collection('cards')
.document(user.uid)
.collection('tokens')
.add({'tokenId': token}).then((val) {
print('saved');
});
});
}
}
And finally, what executes when i push the button:
StripeSource.addSource().then((String token) {
print("Stripe!");
PaymentService().addCard(token);
});
As you can see the code is clearly being triggered, but i guess there is some sort of error with the data var, JavaScript is brand new to me so im sure its some sort of very dumb syntax issue.
From the log image attached the error is context is not defined
functions.firestore.document('cards/{userid}/tokens/{tokenid}')
.onCreate(async (tokenSnap, conetxt) => {
In the above function, you have passed parameter as conetxt and later in the function context is used, because of which it is giving undefined error.
Change the parameter name conetxt to context.
As your provided log output explains : you need to define a reference for your firestore.document function :
functions.firestore.document('cards/{userid}/tokens/{tokenid}')
modify it to :
functions.firestore.documentReference(){
}
I tried to implement firebase functions from the tutorial: https://firebase.google.com/docs/functions/get-started
This is my code bellow. When I try to call the url https://us-central1-skoon-5ed4d.cloudfunctions.net/addMessage I hava an "Error: could not handle the request"
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addMessage = functions.https.onRequest(async (req, res) => {
const original = req.query.text;
const snapshot = await admin.database().ref('/messages').push({original: original});
Firebase console.res.redirect(303, snapshot.ref.toString());
});
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onCreate((snapshot, context) => {
// Grab the current value of what was written to the Realtime Database.
const original = snapshot.val();
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return snapshot.ref.parent.child('uppercase').set(uppercase);
});
I removed async and await and in my log I have Error:
Reference.push failed: first argument contains undefined in property 'messages.original'
at validateFirebaseData (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:1433:15)
at /srv/node_modules/#firebase/database/dist/index.node.cjs.js:1479:13
at Object.forEach (/srv/node_modules/#firebase/util/dist/index.node.cjs.js:837:13)
at validateFirebaseData (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:1462:14)
at validateFirebaseDataArg (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:1421:5)
at Reference.push (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:14087:9)
at exports.addMessage.functions.https.onRequest (/srv/index.js:23:54)
at cloudFunction (/srv/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /worker/worker.js:724:7
at /worker/worker.js:707:11