When I use Firebase Cloud Functions in my Flutter app to create a document inside a collection it works:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.onCreatePost = functions.firestore
.document("/posts/{postId}")
.onCreate(async (snap, context) => {
const doc = snap.data()
const creatorId = doc.creatorId
admin.firestore().collection('feeds').doc(creatorId).set({
Id: creatorId,
isRead: false,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
})
});
But when I try to add the same document inside a subcollection in that document, it does not work:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.onCreatePost = functions.firestore
.document("/posts/{postId}")
.onCreate(async (snap, context) => {
const doc = snap.data()
const creatorId = doc.creatorId
admin.firestore().collection('feeds').doc(creatorId).collection('feedItems').doc(context.params.postId).set({
Id: creatorId,
isRead: false,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
})
});
What am I doing wrong? I do see that the cloud function was completed successfully in the logs, but the docment is not created in my Cloud Firestore.
I would expect neither function to work reliably, because you aren't returning a promise that resolves after the asynchronous work is complete. If you don't return a promise, then Cloud Functions might terminate your function before it's done.
Minimally, you should return the promise returned by set().
return admin.firestore()
.collection('feeds')
.doc(creatorId)
.collection('feedItems')
.doc(context.params.postId)
.set(...)
You should also check the Cloud Functions log for errors. Errors will not show up in your app since the code is running completely outside of it.
I suggest also reviewing the documentation on this.
Related
I've tried many methods such as
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
const docRef = db.collection("users").doc(dynamicDocID).get()
const docRef = db.collection("users").doc(dynamicDocID)
as well as many other and keep getting undefined or a promise that never seems to be resolved
Cant seem to find proper docs on this if anything
Since Cloud Functions for Firebase are written in Node.js, have a look at the Node.js examples in the Firestore documentation.
Based on that:
const docRef = db.collection("users").doc(dynamicDocID)
const document = await docRef.get()
console.log(document.id, document.data())
Or if you can't use await:
const docRef = db.collection("users").doc(dynamicDocID)
return docRef.get().then((document) => {
console.log(document.id, document.data())
})
I am trying to set up a function in Cloud Firestore that will trigger whenever a new document is added to a particular collection. I wish to do it using TypeScript as I'm told its easier to work with when writing asynchronous code. The following JavaScript code works as expected and triggers whenever I add a new document at the specified location:
//This JavaScript code works
import * as functions from 'firebase-functions';
exports.waitReportCreatedJS = functions.firestore
.document('merchant_locations/{merchantId}/wait_period/{waitId}')
.onCreate((snapshot, context) => {
console.log('WaitReportCreated has been triggered');
const merchantId = context.params.merchantId
const waitId = context.params.waitId
console.log(`New wait recorded: ${waitId} at ${merchantId}`);
return snapshot.ref.update({ waitId: waitId })
});
But then when I try to do the same thing using TypeScript, it fails to trigger - nothing at all happens when I add the document:
//But this TypeScript code doesn't seem to even trigger
import * as functions from 'firebase-functions';
export const waitReportCreatedTS = functions.database
.ref('merchant_locations/{merchantId}/wait_period/{waitId}')
.onCreate((snapshot, context) => {
console.log('WaitReportCreated has been triggered');
const merchantId = context.params.merchantId
const waitId = context.params.waitId
console.log(`New wait recorded: ${waitId} at ${merchantId}`);
return snapshot.ref.update({ waitId: waitId })
})
I'm very new to Firestore functions, and have no clue at all what I'm doing wrong. Thanks for any help you can give me.
In your javascript example you faciliate the Firestore Database functions.firestore
.document. However your TypeScript example is using the Realtime Database functions.database.ref.
import * as functions from 'firebase-functions';
export const waitReportCreatedTS = functions.firestore
.document('merchant_locations/{merchantId}/wait_period/{waitId}')
.onCreate((snapshot, context) => {
console.log('WaitReportCreated has been triggered');
const merchantId = context.params.merchantId
const waitId = context.params.waitId
console.log(`New wait recorded: ${waitId} at ${merchantId}`);
return snapshot.ref.update({ waitId: waitId })
I am trying to write a Firebase Cloud function which would write the current time inside the database whenever called:
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
exports.pushDateOfCall = functions.https.onRequest((req, res) => {
const currentTime = new Date();
return admin.database().ref('/dates').push({currentTime: currentTime}).then((snapshot) => {
return res.send("Complete");
}).catch((error) => res.send("Something went wrong"));
});
After deploying the function and calling it from the function's URL, nothing is written inside the database.
Output of firebase functions logs:
Function execution took 1358 ms, finished with status code: 304
P.S. I am running the link from incognito since I wish that whoever calls the link (both authorised and unauthorised) is able to use it.
const currentTime = new Date();
Here currentTime is an object. If you want to store the String of the date, use String(currentTime) as
return admin.database().ref('/dates').push({currentTime: String(currentTime)})
#hkchakladar is right, changing to {currentTime: String(currentTime)} will solve the problem.
However, note that you don't need to return res.send() nor to return the promise returned by the asynchronous push() method. This is shown in the official Firebase video about HTTP Cloud Function, see https://www.youtube.com/watch?v=7IkUgCLr5oA
So your code may be as follows:
exports.pushDateOfCall = functions.https.onRequest((req, res) => {
const currentTime = new Date();
admin
.database()
.ref('dates')
.push({ currentTime: String(currentTime) })
.then(ref => {
res.send('Complete');
})
.catch(error => res.status(500).send('Something went wrong'));
});
I am following a tutorial where I am adding some Firebase Cloud Functions to my project (step 5). I have successfully deployed my cloud function to firebase but nothing happens when I add a new product manually in the Firebase Database console. I discovered that the Firebase cloud function is triggered but it is getting an error: "TypeError: Cannot read property 'productId' of undefined"
What am I doing wrong?
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.sendMessage = functions.firestore
.document('products/{productId}')
.onCreate(event => {
const docId = event.params.productId; // <-- error here
const name = event.data.data().name;
const productRef = admin.firestore().collection('products').doc(docId)
return productRef.update({ message: `Nice ${name}! - Love Cloud Functions`})
});
That tutorial must be out of date. Some things have changed in the Functions SDK when it released version 1.0. You can read about those changes here.
Database triggers are now passed two parameters instead of one. The new context parameter contains the value of wildcards in the reference path:
exports.sendMessage = functions.firestore
.document('products/{productId}')
.onCreate((snapshot, context) => {
const docId = context.params.productId;
If you want to continue with that tutorial, you'll have to manually convert all of its old stuff to new stuff.
OK. So thanks to Dough Stevensson's answer notifying me that the syntax was old I have now a solution:
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();
exports.sendMessage = functions.firestore
.document('products/{productId}')
.onCreate((snapshot, context) => {
const docId = context.params.productId;
const productRef = db.collection('products').doc(docId)
return productRef.update({ message: `Nice ${name}!`})
});
I have an app that takes a New York Times recipe URL, and converts the list of ingredients into a shopping to-do list.
Because the New York Times uses React, none of the data is available via standard scraping - the index.html is mostly blank. I have to use a library like NightmareJS, which uses an Electron browser to fully construct the DOM (including the Javascript) so that I can then scrape that constructed-DOM for data.
But this doesn't seem to work. Here's the code I have included in my /functions/index.js file:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions')
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const Nightmare = require('nightmare')
const Actions = require('nightmare-react-utils').Actions
exports.listify = functions.https.onRequest((req, res) => {
console.log("YOU ARE NOW INSIDE THE LISTIFY FUNCTION!")
Nightmare.action(...Actions)
const nightmare = new Nightmare({ show: false })
const selector = 'ul.recipe-ingredients'
const queryUrl = req.query.url
nightmare
.goto(queryUrl)
.wait()
.evaluate((selector) => {
console.log("YOU ARE NOW INSIDE THE EVALUATE!")
const recipeIngredientsObject = document.querySelector(selector).children
const result = []
const ingredientKeys = Object.keys(recipeIngredientsObject)
ingredientKeys.forEach((key) => {
const ingredientObject = recipeIngredientsObject[key]
const quantityAndIngredient = ingredientObject.children
result.push({
"quantity": quantityAndIngredient[0].innerText,
"ingredient": quantityAndIngredient[1].innerText
})
})
return result
}, selector)
})
When I call this Function from my front-end, I see the first console log in my Firebase logs - "YOU ARE NOW INSIDE THE LISTIFY FUNCTION!" - but I do not see the second message: "YOU ARE NOW INSIDE THE EVALUATE!"
Can I not use NightmareJS with Firebase Functions?
The console.log message will never appear. When you run evaluate, that function is executed inside the context of the headless browser, so will not log to terminal.
Try something like...
.evaluate((selector) => {
return document.querySelector(selector)
}, selector)
.end()
.then(console.log)
To see if it's working at all.