Getting data from cloud firestore using nodejs takes too long - node.js

I am testing firebase with a NodeJs application and when I try to read data from a database that I have created with one collection it gets the data but it takes too much time to log the data on my terminal.
const express = require('express');
const bodyParser = require('body-parser');
const admin = require('firebase-admin');
let serviceAccount = require('./ServiceAccountKey.json');
const app = express();
const port = 3000;
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://database url"
});
let db = admin.firestore();
db.collection('messages').get()
.then((snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.id, '=>', doc.data());
});
})
.catch((err) => {
console.log('Error getting documents', err);
});
I have also tried to write data on the database but I am always getting the following error when I try to do it using the below code:
let docRef = db.collection('test').doc('alovelace');
let setAda = docRef.set({
first: 'Ada',
last: 'Lovelace',
born: 1815
}).then(function() {
console.log('Data saved!');
}).catch(function(error) {
console.log("Gor an error: ", error);
});
I would like to understand what I am doing wrong since I am reading 1 item only and trying to insert one item only. You support is really appreciated.

There may be some backdated dependencies. Try using
npm update

Related

Discord.js/Firestore .where() is not a function

I am trying to integrate my discord bot with firestore. Whenever I try to run a query I get .where is not a function and I don't understand why because everything else seems to work. Here is the relevant code. I have tried the require of firebase at the top of Remove.js and that doesn't seem to do anything.
Here is my thought to how I believe it should be working right now.
I run node . and it then runs my index.js file.
On an interaction create (i.e. a slash command is created) it checks the command file and in this case it is the remove command
It calls execute(interaction, db) where interaction is the interaction slash command and db is the admin.Firestore() db reference from index.js. I am fully able to use get commands (i.e. that first chunk of code works before I try to delete)
Because this is a reference I should be able to call .where() based on the Firestore documentation and yet I am hit with the error "TypeError: db.collection(...).doc(...).collection(...).doc(...).where is not a function"
// Index.js
// General Setup
const { Client, Collection, Intents } = require('discord.js')
const config = require('./config.json')
const fs = require('fs')
// Bot Setup
const myIntents = new Intents();
myIntents.add(Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MEMBERS)
const bot = new Client({intents: myIntents});
// Firebase Setup
const firebase = require('firebase/app')
const fieldValue = require('firebase-admin').firestore.FieldValue
const admin = require('firebase-admin')
const serviceAccount = require('./serviceAccount.json')
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
})
let db = admin.firestore();
// Command Setup
bot.commands = new Collection();
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'))
for (const file of commandFiles) {
const command = require(`./commands/${file}`);
bot.commands.set(command.data.name, command);
}
// Bot Login
bot.once('ready', async () => {
console.log('Wheatley is online!');
});
bot.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) {
return
}
const command = bot.commands.get(interaction.commandName)
if (!command) {
return
}
try {
await command.execute(interaction, db)
} catch (error) {
console.error(error)
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true})
}
});
bot.login(config.bot_token);
///Remove.js
const { SlashCommandBuilder } = require('#discordjs/builders');
require('#firebase/firestore');
module.exports = {
data: new SlashCommandBuilder()
.setName('remove')
.setDescription('Removes object from collection')
.addStringOption(option =>
option.setName('item')
.setDescription('Enter an item in the collection to remove')
.setRequired(true)
),
async execute(interaction, db) {
const itemName = await interaction.options.getString('item')
const itemToDelete = db.collection('items').doc(interaction.guildId).collection('items').doc(itemName);
const doc = await itemToDelete.get();
if(!doc.exists) {
return interaction.reply({
content: `${itemName} does not exist in the collection. Try using /list to check for the right name.`,
ephemeral: true
})
}
const ownerId = interaction.user.id
const snapshot = db.collection('items').doc(interaction.guildId).collection('items').doc(itemName).where("ownerId", "==", ownerId).get();
if(!snapshot.exists) {
return interaction.reply({
content: `You are not the owner of ${itemName}. Please contact owner to delete this from the collection`,
ephemeral: true
})
}
itemToDelete.delete();
return await interaction.reply(`${itemName} was removed from the collection!`)
},
};
You are using where on a document, as where is a query function that is only available to collections.
Just be warned that the snapshot will return an array of snapshots as it is a query, not a single document.
Try this instead:
const snapshot = db.collection('items').doc(interaction.guildId).collection('items').where("ownerId", "==", ownerId).get();

Issue with Firebase Cloud function.. not able to read parameters

I am not uunderstanding why this is not working, as it is basic.
Here is my code:
// Init cloud functions
const functions = require('firebase-functions');
const admin = require('firebase-admin');
// Used to access entire JSON Nodes as Admin...
admin.initializeApp();
exports.verifyIAP = functions.database.ref('/Users/{userid}/IAP/{groupid}/{rdate}')
.onCreate((snapshot, context) => {
const groupId = context.params.groupid;
console.log('GroupID: ', groupId);
const receiptDate = context.params.rdate;
console.log('receipt Date: ', receiptDate);
const userId = context.params.userid;
console.log('UserID: ', userId);
const receipt = snapshot.val().ReceiptData;
console.log('receipt Data: ', receipt);
});
When the function triggers, the log shows all the variables as undefined!?
What am I missing!?
Your function is working fine. I just tested it and the problem can be pointed on how you insert the data. For testing purposes, Here's a sample code I used to insert data and trigger the function:
// Import Admin SDK
var admin = require("firebase-admin");
var serviceAccount = require("./*******.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://********.firebaseio.com/"
});
var db = admin.database();
var ref = db.ref("Users");
ref.set({
"userId" : {
"IAP" : {
"groupId" : {
"rdate" : {
"ReceiptData" : "testVAl"
}
}
}
}
}).then(result => {
console.log('done')
process.exit(0)
});

I need to index firebase data to algolia , rules in firebase for both read and write requires Authentication (auth!=null)

I am using the code described in the algolia docs. It is working when firebase rules allow both read and write without authentication. This does not work with data which requires authentication. What I can do to add auth in below code ?
I tried using firebase-admin, I think this method will work only when rule is changed to allow read for a single uid.
const algoliasearch = require('algoliasearch');
const dotenv = require('dotenv');
const firebase = require('firebase');
const admin = require("firebase-admin");
var serviceAccount = require("./config/serviceAccountKey.json");
// load values from the .env file in this directory into process.env
dotenv.config();
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: process.env.FIREBASE_DATABASE_URL
});
firebase.initializeApp({
databaseURL: process.env.FIREBASE_DATABASE_URL
});
admin
.auth()
.createCustomToken('siddharth')
.then((customToken) => {
console.log(customToken);
firebase.auth().authenticateWithCustomToken(customToken);
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
// admin.auth.createCustomToken('siddharth').then(token => {
// });
const database = firebase.database();
const algolia = algoliasearch(
process.env.ALGOLIA_APP_ID,
process.env.ALGOLIA_API_KEY
);
const index = algolia.initIndex(process.env.ALGOLIA_INDEX_NAME);
database.ref('/questions').once('value', questions => {
const records = [];
questions.forEach(question => {
// get the key and data from the snapshot
const childKey = question.key;
const childData = question.val();
// We set the Algolia objectID as the Firebase .key
childData.objectID = childKey;
// Add object for indexing
records.push(childData);
});
console.log(records);
// Add or update new objects
index
.saveObjects(records)
.then(() => {
console.log('questions imported into Algolia');
})
.catch(error => {
console.error('Error when importing question into Algolia', error);
process.exit(1);
});
});
Since this seems to be a Node.js script that accesses Firebase Authentication by using service credentials with the Admin SDK, you can also use that Admin SDK to access the database. Accessing a Firebase service through the Admin SDK with service credentials gives full administrative access, and bypasses any security rules you may have configured for your database.
In code, change:
const database = firebase.database();
To:
const database = admin.database();

Express JS: Send Databse as Variable / Parameter while requiring a module

Say I have the following code
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const serviceAccount = require("./permissions.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://blah-blah-blah.firebaseio.com"
});
const db = admin.firestore();
app.use("/auth", require("./auth"));
Now the problem is that I have to use the cloud firestore databse functionality, which is curently stored in the variable db, in my auth.js file as well, without using admin.initializeApp a second time. Is there any way to acomplish that, like importing/exporting the db variable etc.
This is where I am using it in auth.js:
const express = require("express");
const auth = express.Router();
db.collection("data")
.doc("sample")
.get()
.then(
document => {
if (document.exists) {
return done(null, {
id: user.id,
name: user.name,
email: user.email
});
} else {
//create document
}
},
err => {
//handle error
}
);
Of course, right now db will be undefined, which is the problem I need to tackle
Since version 1.0.0 of the Firebase SDK for Cloud Functions you have to initialize with admin.initializeApp();, see the doc here.
Then, to interact with Firestore, you just need to use the Admin SDK, for example as follows:
admin.firestore().collection('....').get();
So, if I understand correctly your question, the following changes should do the trick:
index.js
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
//const db = admin.firestore(); not sure you need that here, it depends if you interact (or not) with Firestore in index.js
app.use("/auth", require("./auth"));
auth.js
const admin = require("firebase-admin");
const db = admin.firestore();
//....
db.collection("data")
.doc("sample")
.get()
.then(
document => {
if (document.exists) {
return done(null, {
id: user.id,
name: user.name,
email: user.email
});
} else {
//create document
}
},
err => {
//handle error
}
);
//....

Node.js cloud function "firestore set() inside get() if not exists" is not working correctly?

Here is I'm trying to achieve
if user is exist in firestore
show the data
else
add it to firestore
And following is my code
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
var db = admin.firestore();
const settings = {timestampsInSnapshots: true};
db.settings(settings);
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function save(agent) {
const usersRef = db.collection('users').doc('someid');
usersRef.get().then(function(doc) {
if(doc.exists) {
let existingUser = doc.data();
console.log("Document is already exists " + existingUser.userName);
agent.add('Hello ');
} else {
console.log("Document creation is started");
usersRef.set({
userName : 'somename'
});
agent.add('Welcome ');
}
}).catch(function(error) {
console.error("Error writing document: ", error);
agent.add('Failed to login!');
});
}
let intentMap = new Map();
intentMap.set('dialogflow-intent-name',save);
agent.handleRequest(intentMap);
});
But the execution of above code it starts the cloud function and terminated first and my chatbot doesn't get any response but after execution log is like
Function execution started
Function execution took 404 ms, finished
with status code: 200
"Document is already exists someusername"
DocumentReference.set returns a promise, and you are not waiting for it to finish. So it should work if you change your code from:
usersRef.set({
userName : 'somename'
});
... rest of the code
to
usersRef.set({
userName : 'somename'
}).then(result => {
... rest of the code
})

Resources