I need to execute cloud functions on a database that is not the default one, but when I try to load it I get this error:
your textError: Can't determine Firebase Database URL.
This is my code:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
const app2 = admin.initializeApp(
{
databaseUrl: "{my_db_url}",
}, "app2");
exports.MyFunction = functions.pubsub.schedule("* * * * *") .timeZone("Europe/Rome") .onRun((context) => {
...
const database = admin.database(app2);
...
});
I cannot find any solution in the documentation.
I tried to look in the documentation or for people with the same problem, but I didn't find any solution.
In the databaseUrl, I'm pasting the database url I copy from the Firebase console.
Related
I'm trying to use Firestore from Cloud functions package like this:
export async function deleteDocRecursively(docRef) {
await Firestore.recursiveDelete(docRef);
}
This works:
const {Firestore} = require('#google-cloud/firestore');
This doesn't work:
import {Firestore} from '#google-cloud/firestore';
I get this error:
TS2339: Property 'recursiveDelete' does not exist on type 'typeof Firestore'.
https://www.npmjs.com/package/#google-cloud/firestore
As mentioned in the documentation, recursiveDelete is a method on an instance of Firestore class and not a static method on the class itself. Try:
import { Firestore } from '#google-cloud/firestore';
// const { Firestore } = require('#google-cloud/firestore');
const db = new Firestore();
export async function deleteDocRecursively(docRef) {
await db.recursiveDelete(docRef); // <-- not 'Firestore'
}
You are using client firestore inside firebase functions instead you should use the one which comes with admin one.
As you are using client firestore
const {Firestore} = require('#google-cloud/firestore');
Above one is working and
import {Firestore} from '#google-cloud/firestore';
Is being failed and getting below error
Property 'recursiveDelete' does not exist on type 'typeof Firestore'.
To get it work you have to use the admin one as this will run on the server.
As Firebase client SDK is meant to run in a client-side environment hence we use Client SDK using firebaseConfiguration listed in the firebase console.
While in firebase functions by initializing the Firebase Admin SDK with admin.initializeApp(), we can perform actions on behalf of your users and take advantage of the security and management features provided by Firebase.
When using firebase function it is advisable to use admin services as stated in the docs
If you have configured your firebase functions with typescript then follow this:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();
const firestore = admin.firestore();
exports.deleteDocRecursively = functions.https.onRequest(async (req, res) => {
// Delete Recursively
const documentRef = firestore.collection("users").doc("<doc_id of doc to be deleted>");
await firestore.recursiveDelete(documentRef);
});
If you have configured your firebase functions with javascript follow this:
const = functions require("firebase-functions");
const = admin require("firebase-admin");
admin.initializeApp();
const firestore = admin.firestore();
exports.deleteDocRecursively = functions.https.onRequest(async (req, res) => {
// Delete Recursively
const documentRef = firestore.collection("users").doc("<doc_id of doc to be deleted>");
await firestore.recursiveDelete(documentRef);
});
For more information go through these links:
Thread using recursiveDelete
I have two applications, each belonging to a different firebase project.
I want to write to both Firestore with the same transaction.
How can I do this?
import admin from "firebase-admin";
const primaryFirebase = admin.initializeApp();
const secondaryFirebase = admin.initializeApp({ credential }, "secondary");
const primaryFirestore = primaryFirebase.firestore();
const secondaryFirestore = secondaryFirebase.firestore();
const bookId = "<book ID>";
const comment = { body: "some text" };
const primaryBookReference = primaryFirestore.collection("book").doc(bookId);
if ((await primaryBookReference.get()).exists) return;
const secondaryBookReference = secondaryFirestore.collection("book").doc(bookId);
if ((await secondaryBookReference.get()).exists) return;
// TODO: same transaction
await primaryBookReference.collection("comment").add(comment);
await secondaryBookReference.collection("comment").add(comment);
There is no way to run a transaction across Firestore instances. You will have to find another way to write the data, for example you might check if a three-phase commit is possible across two databases.
I want to retrieve the field value from a document snapshot which is the URL of a file in firebase storage and delete the file from firebase storage also the firestore document if the time of creation of the doc is before 24 hrs.
I am able to delete expired firestore documents successfully with the code below:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { firestore } = require("firebase-admin");
admin.initializeApp();
exports.removeExpiredDocuments = functions.pubsub.schedule("every 1 hours").onRun(async (context) => {
const db = admin.firestore();
const now = firestore.Timestamp.now();
const ts = firestore.Timestamp.fromMillis(now.toMillis() - 86400000); // 24 hours in milliseconds = 86400000
const snapshots = await db.collection("photos").where("timestamp", "<", ts).get();
let promises = [];
snapshots.forEach((snap) => {
promises.push(snap.ref.delete());
});
return Promise.all(promises);
});
but I don't know how to retrieve the field value(URL of file) from the document snapshot within the forEach block and delete the file from firebase storage.
Here's the firestore database:
The field value of photourl is to be retreived.
Thanks in advance!
I think code look like :
//some code ....
snap.docs.map((doc) => {
if (doc.exist) {
var url = doc.data().photourl;
//do something logic call to firestorage and deleted data base on url get
//write logic deleted url firebase after deleted success firestorage
}
});
I am building an Express.js app, using the Firebase Admin SDK for several features such as ID Token validation and Cloud Firestore access. In my main app.js file, I am initializing the app as:
const admin = require('firebase-admin')
const serviceAccount = require('../config/account-credentials.json')
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://databaseurl.firebaseio.com'
})
In another file, all I'm doing is importing:
const admin = require('firebase-admin')
I am able to call admin.auth().verifyIdToken and verify ID tokens just fine. However when I call app.database(), it complains that the app is never initialized. Inititalizing the app again creates a new error saying:
The default Firebase app already exists. This means you called initializeApp() more than once without providing an app name as the second argument. In most cases you only need to call initializeApp() once. But if you do want to initialize multiple apps, pass a second argument to initializeApp() to give each app a unique name.
Do I need to create multiple apps with different names for this to work? Or how can I use one app throughout the project.
You should initialize your application exactly once and then re-use that reference. There are various ways to do this, but the way I prefer is to import firebase.ts (which initializes the Firebase application and services) into my index.ts (or whatever your entry point is). Then I pass a reference to any other files that need a particular service. I'm using TypeScript, so adjust this as needed if you're using vanilla JS.
firebase.ts
import * as admin from 'firebase-admin';
// Initialize our project application
admin.initializeApp();
// Set up database connection
const firestoreDb: FirebaseFirestore.Firestore = admin.firestore();
firestoreDb.settings({ timestampsInSnapshots: true });
export const db = firestoreDb;
My index.ts file will import it:
import { db } from './firebase';
Then when I set up my routes with Express, I'll have each route in another file with its own function. Then pass in the db reference to any that need it.
app
.route('events')
.get((req: Request, res: Response) => {
get_events(db, res);
return;
});
Here is a blog post where I explain it a bit more:
https://medium.com/#jasonbyrne/how-to-structure-a-serverless-rest-api-with-firebase-functions-express-1d7b93aaa6af
If you don't like the dependency injection method or prefer to lazy-load only the services you nee, you could go another it a different way. In that method you'd have your firebase.js file (or whatever you call it) that you import to any pages that need it and call a function to load that service. Here I'm just doing Firestore, but you could create similar functions for references to other services.
Just typed this up as a sample...
import * as admin from 'firebase-admin';
// Initialize our project application
admin.initializeApp();
// Database reference, not yet loaded
let db: FirebaseFirestore.Firestore | null = null;
// Get cached db reference or create it
export function getDatabaseReference() {
if (db === null) {
db = admin.firestore();
}
return db;
}
I hope this helps. Let me know if you have any questions.
I got this working very nicely in a microservice API in cloudRun using global.
const admin = require('firebase-admin');
global.GeoFirestore = require('geofirestore').GeoFirestore;
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
global.db = admin.firestore();
global.admin = admin;
In another module I can access collections:
var docRef = db.collection("collection").doc(doc.id);
docRef.update({state}).then((doc) => {
console.log(doc)
}).catch((error) => {
console.log("Error getting document:", error);
});
For working on a GeoFirestore GeoPoint I needed to have admin globally:
const geofirestore = new GeoFirestore(db);
const geocollection = geofirestore.collection('bin');
var objectToBeStored = {
...data,
coordinates: new admin.firestore.GeoPoint(coordinates.lat, coordinates.lng)
}
geocollection.add(objectToBeStored ).then((docRef) => {
console.log(`added data: ${docRef.id}`);
}).catch((error) => {
console.log(`error: ${error}`);
})
Here's how I did it: I created a wrapper around the admin.firestore() etc functions I needed, and I import that and use it in all my other functions:
FunctionsShared.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
export const FunctionsShared = {
firestore: () => admin.firestore()
};
MyFirebaseFunction.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import {FunctionsShared} from './FunctionsShared';
export getStaleDocumentsQuery = functions.https.onCall(() => {
// Use FunctionsShared.firestore() instead of admin.firestore()
return FunctionsShared.firestore()
.collection('mirror')
.where('updated', '<', oneMonthAgo)
.orderBy('updated')
.limit(limit);
}
I'm starting to use firebase cloud functions, and I have trouble reading an entry "Hello" from my database tree :
I'm trying to read the "Hello" value inside HANDLE/suj1/part1 from my tree. I am using a firebase cloud function that is triggered when I create an other entry with an IOS Application in the database inside "INTENT". The functions gets called well but every time I try to read the "Hello" value , it returns a null value in my firebase console where I expect it to return "Hello".
Here is the code I use :
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp()
exports.match = functions.database.ref('INTENT/{userid}').onCreate(snapshot => {
const user = snapshot.key
return admin.database().ref('HANDLE/suj1/part1').once('value', (snap) => {
const hello = snap.val()
console.log(hello) // Null
});
Can someone tell what am I doing wrong ?
I found out with this line and Frank's help:
admin.database().ref().once('value', (snap) => { console.log(JSON.stringify(snap.val())); });
That I had added a whitespace at the end of "HANDLE " in my path, which does not appear in the Firebase console. I had to delete the branch and create an other one.
Try this:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp()
exports.match =
functions.database.ref('OTHERLOCATION/{userid}').onCreate((snapshot) => {
const user = snapshot.key
return admin.database().ref().child('HANDLE/suj1').once('value', function(snap) => {
const hello = snap.val().part1
console.log(hello) // "Hello"
});
please try this
const userName = admin.database().ref('/HANDLE/suj1/part1').once('value',function(snapshot) {
const hello = snapshot.val();
console.log(hello);
});