Firebase Functions, admin.database().ref(...).get() is not a function - javascript

I am working on an Android Application and am using firebase as the back end for it. I am trying to get a notification system working that relies on listening to changes in the database. Having problems though as I am getting the following error. Wondered if anyone would be able to help, any extra code can be supplied.
Firebase Function
'use-strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref("Notifications/{user_id}/{notification_id}").onWrite((data, context)=>{
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log("User ID : " + user_id + " | Notification ID : " + notification_id);
return admin.database().ref("Notifications/" + user_id + "/" + notification_id).get().then(queryResult => {
const job_id = queryResult.data().Job;
const from_data = admin.database().ref("Jobs/" + job_id).get();
const to_data = admin.database().ref("Users/" + user_id).get();
return Promise.all([from_data, to_data]).then(result => {
const job_name = result[0].data().advertName;
const to_name = result[1].data().fullName;
console.log("JOB : " + job_name + " | TO : " + to_name);
return undefined;
});
});
});
Function Error

It looks like you're mixing up the Realtime Database and Firestore APIs. Firebase Realtime Database APIs doens't provide a get() method to fetch data. For that, you use once() on a Reference object.

The error is pretty explicit: there is no get function in the a Firebase Realtime Database.
You seem to be trying to use Cloud Firestore, which is available under admin.firestore(). So something like:
const from_data = admin.firestore().doc("Jobs/" + job_id).get();
const to_data = admin.firestore().doc("Users/" + user_id).get();
For full samples see the NODE.JS tab in the Getting started and other Firestore documentation.

Related

database firebase: when reading, there is no output

I'm trying to read the value from firebase realtime database, but there is no output.
var text = login;
var encoded = btoa(text);
const db = firebase.database();
const func1 = db.ref('users/' + encoded + '/money');
func1.on('value', (snapshot) => {
var data = snapshot.val();
console.log(data);
document.getElementById('some-h1').innerHTML="<h1 class=\"summary\" id=\"some-h1\">" + data + "</h1>";
}, (errorObject) => {
console.log('The read failed: ' + errorObject.name);
});
As I said, there is no output, when the code is executed.
I'll be really thankful, if someone will reply with the solution.
I was trying to set the value of key from my database to be set as text, and I was expecting to show but there is nothing.

How do I hide my API key in script.js file using dotenv

I want to use dotenv to hide my Api key.
when I remove require('dotenv').config(); from my code and put my API key in apiKey: process.env.API_KEY, instead of process.env.API_KEY the code is working.
I have install dotenv and also checked my dependencies
I have created .env folder and mentioned API_KEY=2947****
I have created .gitignore file and placed .env in it
but when I tried to use it in my script.js file its not working
require('dotenv').config();
let weather = {
apiKey: process.env.API_KEY,
fetchWeather: function (city) {
fetch(
"https://api.openweathermap.org/data/2.5/weather?q=" +
city +
"&units=metric&appid=" +
this.apiKey
)
.then((response) => {
if (!response.ok) {
alert("No weather found.");
throw new Error("No weather found.");
}
return response.json();
})
.then((data) => this.displayWeather(data));
},
displayWeather: function (data) {
const { name } = data;
const { icon, description } = data.weather[0];
const { temp, humidity,temp_min,temp_max } = data.main;
const { speed } = data.wind;
// const { sunrise, sunset } = data.sys;
document.querySelector(".city").innerText = "Weather in " + name;
document.querySelector(".icon").src ="https://openweathermap.org/img/wn/" + icon + ".png";
document.querySelector(".description").innerText = description;
document.querySelector(".temp").innerText = temp + " °C";
document.querySelector(".humidity").innerText ="Humidity: " + humidity + "%";
document.querySelector(".wind").innerText ="Wind speed: " + speed + " km/h";
document.querySelector(".min").innerText ="Min Temp: " + temp_min + " °C";
document.querySelector(".max").innerText ="Max Temp: " + temp_max + " °C";
// document.querySelector(".sunrise").innerText =
// "Sunrise: " + sunrise + " °C";
// document.querySelector(".sunset").innerText =
// "Sunset: " + sunset + " °C";
document.querySelector(".weather").classList.remove("loading");
// document.body.style.backgroundImage =
// "url('https://source.unsplash.com/1600x900/?" + name + "')";
},
search: function () {
this.fetchWeather(document.querySelector(".search-bar").value);
},
};
document.querySelector(".search button").addEventListener("click", function () {
weather.search();
});
document
.querySelector(".search-bar")
.addEventListener("keyup", function (event) {
if (event.key == "Enter") {
weather.search();
}
});
weather.fetchWeather("Pune");
I think you misunderstood how "hiding your Api key" works.
First of all you cant really hide your API key from the client, since the client needs to use it in order to talk to the (API-)server. Where you want to hide your key from is your source control, this mainly to be able to use different keys in different environments without having to change the source code in your source control. Secondly, you need a build step in order to use things like dot env. If your script.js is directly included in an html file you cannot use dotenv in there. This is how env's are used normally:
You have some source code, src.js which needs secrets to work (eg API keys), these are referenced in the source code using process.env.[NAME_OF_THE_VARIABLE]
Then your source code is build using for example webpack vite babel etc., during this build process all references of process.env.[...] are replaced with the respective content in .env
the result is a file dest.js which contains the secrets in plain text with no reference to process.env.[...] anymore, this file is which can be referenced in html directly
I hope this clears things up
As Alex has said, there's no way to hide it from the browser. You could add it when bundling but it would still be in the source code.
So what are the available options
You could move the whole weather API fetch to your custom server and create an endpoint with which users can get the required data.

Trying to get multiple messages from an Azure Storage Queue

I have a node.js Function App which I'm trying to use to retrieve a specific message from a storage queue in order to delete it. It doesnt seem like there is a method to get a specific message by ID, so I'm trying to read all the messages, or at least 32 of them, then find the message to delete by ID.
My problem is I cant seem to figure out how to format the request to specify the number of messages to receive. I am trying to add the option "numberOfMessages" based on this documentation: https://learn.microsoft.com/en-us/javascript/api/#azure/storage-queue/queuereceivemessageoptions?view=azure-node-latest##azure-storage-queue-queuereceivemessageoptions-customheaders
Here is what I have right now that isn't working:
const response = await queueClient.receiveMessages({"numberOfMessages": 32});
context.log("response: " + JSON.stringify(response.receivedMessageItems));
context.log("received messages length: " + response.receivedMessageItems.length);
response is:
[Information] response: [{"messageId":"XXXXXX","insertedOn":"2022-08-28T06:12:45.000Z","expiresOn":"2022-09-04T06:12:45.000Z","popReceipt":"XXXXXXXXX","nextVisibleOn":"2022-08-30T14:57:37.000Z","dequeueCount":858,"messageText":"XXXXXXX"}]
[Information] received messages length: 1
How should I be formatting the option(s)???
edit:
Here is the complete code of index.js in my function app (with redactions):
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
const message = req.body;
const ackType = message.ackType;
if (ackType == 1){
const { QueueServiceClient, StorageSharedKeyCredential } = require("#azure/storage-queue");
const account = "MY_ACCOUNT_NAME";
const accountKey = "MY_ACCOUNT_KEY";
const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
const queueServiceClient = new QueueServiceClient(
`https://${account}.queue.core.windows.net`,
sharedKeyCredential,
{
retryOptions: { maxTries: 4 } // Retry options
}
);
const queueName = "MY_QUEUE_NAME";
const queueClient = queueServiceClient.getQueueClient(queueName);
const response = await queueClient.receiveMessages({"numofmessages": 32});
context.log("response: " + JSON.stringify(response));
context.log("receivedMessageItems: " + JSON.stringify(response.receivedMessageItems));
context.log("received messages length: " + response.receivedMessageItems.length);
}
context.res = {
status: 200 /* Defaults to 200 */
};
}
Here is the queue I am connecting to:

ETH ENS Web3 - How to get Registrant

I've following code snippet to get the "Controller" (The owner of the domain) but I need to get the "Registrant" of provided ENS name
const Web3 = require("web3")
const web3 = new Web3("https://cloudflare-eth.com");
var ens = web3.eth.ens;
var names = ['jtimberlake.eth', 'usman.eth'];
(async () => {
for (let domainName of names) {
// console.log('checking: ' + domainName);
const addr = await getDomain(domainName);
console.log(addr);
}
})();
async function getDomain(word) {
try {
const addr = await ens.getAddress(`${word}`)
// console.log(addr);
return addr;
} catch (err) {
console.error(err);
return;
}
}
Can you please guide how I can get the "Registrant" of provided ENS name e.g. jtimberlake.eth
Web3 is a steaming pile. It doesn't do it with its methods. The registrant used to be called the deed owner, and the controller the owner. Now it is registrant and controller. That's why the method name makes no sense at all now in Web3.js - it never got updated, and never was useful for this in the first place.
The good news is there is a simple way. You can derive the token ID of the ENS domain from its name with the getRegistrant function below. https://docs.ens.domains/dapp-developer-guide/ens-as-nft
The name variable in the docs is superfluous and does nothing. You will need to instantiate ethersjs (npm install ethers) to get the ethers methods to work. You have to use this crazy number of functions because the token ID of an ENS domain/NFT is a uint256. JavaScript hates those natively.
The web3 method to find the controller also still works well if you ever need that. I suggest putting it in another function.
const getRegistrant = (domainName) => {
const BigNumber = ethers.BigNumber
const utils = ethers.utils
const labelHash = utils.keccak256(utils.toUtf8Bytes(domainName))
const derivedTokenId = BigNumber.from(labelHash).toString()
//You need to instantiate the ENSRegistrarContract with its ABI and address. e.g. const ENSRegistrarContract = new web3.eth.Contract(ABI, ADDRESS)
ENSRegistrarContract.methods.ownerOf(derivedTokenId).call()
.then(function(registrant) {
console.log(domainName + "is owned by: " + registrant)
return registrant
})
}
const getController = (domainName) => {
//getOwner fetches the controller of a domain confusingly.
web3.eth.ens.getOwner(domainName).then(function(controller) {
console.log(domainName + "is controlled by: " + controller)
return controller
})
}

subcollection not getting exported through Firestore export cloud function

Below is my cloud function for taking Firestore export to a GCP bucket. I am trying to pass the CollectionIDs name through 'collectionsToBackup' const which I am creating by appending the current_date to the name as my subcollection names are of the format: sub_collection_name_yyyymmdd. The function deploys however when its executed, it does not take the export of my subcollection: most_valuable_items_yyyymmdd for that day. Could someone help me please identify what could be wrong with my function?
Code:
const firestore = require('#google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();
const bucket = 'gs://BUCKET_NAME'
const date_ob = new Date();
const date = ("0" + date_ob.getDate()).slice(-2);
const month = ("0" + (date_ob.getMonth() + 1)).slice(-2);
const year = date_ob.getFullYear();
const new_date= (year + month + date);
const collectionsToBackup= ("'" + "most_valuable_items" + "_" + new_date + "'");
exports.scheduledFirestoreBackup = (event, context) => {
const databaseName = client.databasePath(
// process.env.GCLOUD_PROJECT,
"f-2",
'(default)'
);
return client
.exportDocuments({
name: databaseName,
outputUriPrefix: bucket,
collectionIds: [collectionsToBackup]
})
.then(responses => {
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
return response;
})
.catch(err => {
console.error(err);
});
};
Your problem seems related to the querying and return of information with Firestore. As explained in this other similar case from the Community here, you will need to consider the limit of the queries in Firestore.
This limit is related to the possibility and functions that would allow you to query the subcollections, so they are sent to your bucket. Querying in Firestore is a shallow process, where, unfortunately, you can't return the whole collection and its own subcollections at once. It will be needed for you to read every subcollection, so you have its data as well as the parent collection.
So, to summarize, it's not about your code being wrong, but about changing the way you are reading your data - both collections and subcollections - so you load the data and then, send it over to the bucket. This answer here clarifies more on possibilities.
Let me know if the information clarified your doubts!

Categories