Pay per for each get method in a firebase function? - javascript

Hey im trying to figuring out if i have a firebase function and inside 4 get methods like this
export default functions
.runWith(runtimeOpts)
.firestore.document("ParentComment/{commentID}")
.onCreate(async (snap, context) => {
try {
const db = admin.firestore();
const { videoID, author, text,videoowner } = snap.data() || {};
const ref = db.doc(`videos/${videoID}`);
const videouid = await db.doc(`videos/${videoID}`).get();
const userSnap = await db.doc(`meinprofilsettings/${author}`).get();
const { commentID } = context.params;
const recoveringuser1 = await db.doc(`Recovering/${videoowner}`).get();
const recoveringuser2 = await db.doc(`Recovering/${author}`).get();
…
do i have to pay for each get method?
or does it count as 1 read?

The pricing elements for Firestore in play here are:
Document Reads: as the name implies, you will be charged for each document that your code causes to be read from the database on the server. Since you are reading 4 individual documents, there are 4 charged document reads
Network Bandwidth: you may also be charged for the bandwidth that is consumed for transferring the data. If the Cloud Function and Firestore are in the same region, this charge is waved.
For more on this, I recommend reading the Firestore pricing page in the documentation.

Related

Data not returning from async function with database connection

The goal is to call a function from my main script that connects to a database, reads a document from it, stores pieces of that document in a new object, and returns that object to my main script. The problem is I cannot get it all to work together. If I try one thing, I get the results but my program locks up. If I try something else I get undefined results.
Long story short, how do I open a database and retrieve something from it to another script.
The program is a quiz site and I want to return the quiz name and the questions.
const myDb = require('./app.js');
var myData = myDb.fun((myData) => {
console.log(myData.quizName);
});
Here is the script that tries to open the database and find the data
const { MongoClient } = require("mongodb");
const {mongoClient} = require("mongodb");
const uri = connection uri goes here but my name is hard coded into it at the moment so I removed for privacy
const client = new MongoClient(uri);
const fun = async (cback) => {
try {
await client.connect();
const database = client.db('Quiz-Capstone');
const quizzes = database.collection('Quiz');
const query = {quizName: "CIS01"};
const options = {
sort: {},
projection: {}
};
const quiz = await quizzes.findOne(query, options);
var quizObject = {
quizName: quiz.quizName,
quizQuestions: quiz.quizQuestions
}
//console.log(testOb);
} finally {
await client.close();
cback(quizObject);
}
}
fun().catch(console.dir);
module.exports = {
fun: fun
}
UPDATE: Still stuck. I have read several different threads here about asynchronous calls and callbacks but I cannot get my function located in one file to return a value to the caller located in another file.

AWS Lambda - Only getting answer after the second test trigger

I'm developing an AWS Lambda in TypeScript that uses Axios to get data from an API and that data will be filtered and be put into a dynamoDb.
The code looks as follows:
export {};
const axios = require("axios");
const AWS = require('aws-sdk');
exports.handler = async (event: any) => {
const shuttleDB = new AWS.DynamoDB.DocumentClient();
const startDate = "2021-08-16";
const endDate = "2021-08-16";
const startTime = "16:00:00";
const endTime = "17:00:00";
const response = await axios.post('URL', {
data:{
"von": startDate+"T"+startTime,
"bis": endDate+"T"+endTime
}}, {
headers: {
'x-rs-api-key': KEY
}
}
);
const params = response.data.data;
const putPromise = params.map(async(elem: object) => {
delete elem.feat1;
delete elem.feat2;
delete elem.feat3;
delete elem.feat4;
delete elem.feat5;
const paramsDynamoDB = {
TableName: String(process.env.TABLE_NAME),
Item: elem
}
shuttleDB.put(paramsDynamoDB).promise();
});
await Promise.all(putPromise);
};
This all works kind of fine. If the test button gets pushed the first time, everything seems fine and is working. E.g. I received all the console.logs during developing but the data is not put into the db.
With the second try it is the same output but the data is successfully put into the Db.
Any ideas regarding this issue? How can I solve this problem and have the data put into the Db after the first try?
Thanks in advance!
you need to return the promise from the db call -
return shuttleDB.put(paramsDynamoDB).promise();
also, Promise.all will complete early if any call fails (compared to Promise.allSettled), so it may be worth logging out any errors that may be happening too.
Better still, take a look at transactWrite - https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#transactWrite-property to ensure all or nothing gets written

Using google apis in firebase funcion

I would like to use the google iot core api from a firebase function.
It all works, but it is very slow. I think is due to the authentication process that needs to be carried out one very call. Is there a way to speed this up?
Right now I have this:
function getClient(cb) {
const API_VERSION = 'v1';
const DISCOVERY_API = 'https://cloudiot.googleapis.com/$discovery/rest';
const jwtAccess = new google.auth.JWT();
jwtAccess.fromJSON(serviceAccount);
// Note that if you require additional scopes, they should be specified as a
// string, separated by spaces.
jwtAccess.scopes = 'https://www.googleapis.com/auth/cloud-platform';
// Set the default authentication to the above JWT access.
google.options({ auth: jwtAccess });
const discoveryUrl = `${DISCOVERY_API}?version=${API_VERSION}`;
google.discoverAPI(discoveryUrl, {}).then( end_point => {
cb(end_point);
});
}
And this allows me to do:
export function sendCommandToDevice(deviceId, subfolder, mqtt_data) {
const cloudRegion = 'europe-west1';
const projectId = 'my-project-id;
const registryId = 'my-registry-id';
getClient(client => {
const parentName = `projects/${projectId}/locations/${cloudRegion}`;
const registryName = `${parentName}/registries/${registryId}`;
const binaryData = Buffer.from(mqtt_data).toString('base64');
const request = {
name: `${registryName}/devices/${deviceId}`,
binaryData: binaryData,
subfolder: subfolder
};
client.projects.locations.registries.devices.sendCommandToDevice(request,
(err, data) => {
if (err) {
console.log('Could not update config:', deviceId);
}
});
});
}
The way that I've found to speed it up is to avoid doing the authentication. I've solved it doing this:
const google = new GoogleApis();
const API_VERSION = 'v1';
const DISCOVERY_API = 'https://cloudiot.googleapis.com/$discovery/rest';
const jwtAccess = new google.auth.JWT();
jwtAccess.fromJSON(serviceAccount);
// Note that if you require additional scopes, they should be specified as a
// string, separated by spaces.
jwtAccess.scopes = 'https://www.googleapis.com/auth/cloud-platform';
// Set the default authentication to the above JWT access.
google.options({ auth: jwtAccess });
const discoveryUrl = `${DISCOVERY_API}?version=${API_VERSION}`;
var googleClient;
google.discoverAPI(discoveryUrl, {}).then( client => {
//cb(end_point);
googleClient = client;
});
// Returns an authorized API client by discovering the Cloud IoT Core API with
// the provided API key.
function getClient(cb) {
cb(googleClient);
}
But when happens then when the client expires? Is there any good solution from using google apis from firebase functions?
The problem may be the discovery pieces. There's a direct IoT Core admin REST API, so you don't have to use discovery...I think. I haven't worked with the Firebase Functions, but they're roughly equivalent to the Google Cloud Functions which may end up working here also. The code we (in a live demo we did) ran to do what you're doing is here if you wanted to tinker around and see if you can get this running in a Firebase Function.

Streaming data from Firebase Realtime Database

I have over 20k documents in my Realtime Database. I need to stream them, but I'm not even sure how to get started with it. This is kind of what I was trying to go for
sendEmail.get('/:types/:message', cors(), async (req, res, next) => {
console.log(5);
const types = JSON.parse(req.params.types);
console.log('types', types);
let recipients = [];
let mails = [];
if (types.includes('students')) {
console.log(1);
const tmpUsers = await admin.database().ref('Users').orderByChild('student').equalTo(true).once('value').then(r => r.val()).catch(e => console.log(e));
recipients = recipients.concat(tmpUsers);
}
if (types.includes('solvers')) {
console.log(2);
let tmpUsers = await admin.database().ref('Users').orderByChild('userType').equalTo('person').once('value').then(r => r.val()).catch(e => console.log(e));
tmpUsers = tmpUsers.concat(arrayFromObject(await admin.database().ref('Users').orderByChild('userType').equalTo('company').once('value').then(r => r.val()).catch(e => console.log(e))));
recipients = recipients.concat(tmpUsers);
}
});
But this code causes my server to run out of memory. Someone suggested streams in my previous question, but as much as I like the idea, I have no idea how to actually do the streaming. I know it should be something like:
const fs = require('fs');
const readStream = fs.createReadStream('path goes here');
const data = [];
readStream.on('data', chunk => {
data.push(chunk);
})
readStream.on('end', () => {
console.log(data);
res.end(data);
});
But how on earth do I pass a firebase query into the path?
I tried this, but it said Argument type Promise is not assignable to parameter type PathLike, which makes sense, but how do I get around it?
const users = fs.createReadStream(admin.database().ref('News').once('value').then(r => r.val()))
To summarize: How do I stream data from a Firebase realtime database?
Edit:
How is that a duplicate? These are 2 completely different questions. The starting code is the same but the ways of solving I'm asking about are completely different
Realtime Database doesn't have any streaming APIs. When you perform a query, the entire result set is always loaded into memory in one shot.
A possible alternative is to page through the results using limitToFirst() along with some query ordering that allows you to perform a subsequent query after the first batch of items is processed, picking up where the last query left off.

Firebase Firestore Cloud Function Never Execute

I made Firestore Could Function Where I have Database Like this
'posts/{postId}/comments/{commentId}'
and Function I made To Increase Field In PostId when New Comment Added
the Funtion has Deploy But it`s Never Execute when adding New Comment
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.comment= functions.firestore
.document('posts/{postId}/comments/{commentId}')
.onWrite((change, context) => {
const commentId = event.params.commentId;
const postId = event.params.postId;
const docRef = admin.firestore().collection('posts').doc(postId);
return docRef.update({numberOfComments:200});
});
I Added Many Comment Even Executions is 0
change this:
const commentId = event.params.commentId;
const postId = event.params.postId;
into this:
const commentId = context.params.commentId;
const postId = context.params.postId;
more info here:
https://firebase.google.com/docs/functions/beta-v1-diff
Before Firebase SDK (<= v0.9.1) version event.params.id was worked. but Now (v1.0.0) android provide documentation to use context.params.id.
Use context insted of event, your problem will be solve.
const commentId = event.params.commentId;
const postId = event.params.postId;
Thanks.

Categories