Get Value Key pair from Firebase with Node.js function - node.js

Ok, I am using Algolia for handling search within my app. The following code adds whatever is in my database to my Algolia Index. However, whenever the data is imported, all of the values in a firebase node get placed under "text" in the Algolia Index.
How can make it to where it is stored as the key value pair found in Firebase.
i.e.
address: 1234 Main St.
VS. / (Instead of)
text:
address: 1234 Main St.
My Code:
exports.indexentry = functions.database
.ref('/blog-posts/{blogid}/text')
.onWrite(event => {
const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME);
const firebaseObject = {
text: event.data.val(),
objectID: event.params.blogid,
};
});

So what you are missing here, is the pushing of the data to Algolia. What you can do if you want to have all the firebase data in an object, is assigning it to a new object, as well as the objectID
exports.indexentry = functions.database
.ref('/blog-posts/{blogid}/text')
.onWrite(event => {
const index = client.initIndex(ALGOLIA_POSTS_INDEX_NAME);
const firebaseObject = Object.assign({}, event.data.val(), {
objectID: event.params.blogid,
});
index.saveObject(firebaseObject); // .then or .catch as well
});
Does that make sense?

Related

Implementation of a global search for chats in telegram tdlib

I'm trying to replicate the global chat search as in telegram.
I'm using getChats method for searching, but the problem is that the method only returns a list of ids.
In addition to the id, I would also like to get the name and avatar of the chat.
Therefore, I have to go through the chatids in the forEach and for each id call the getChat method that returns the data I need. This, in turn, causes severe problems with the query execution time. (14 seconds). In a telegram, the search takes ~2 seconds. I don’t know how they did it, I re-read all the documentation and did not find a method that would allow me to pass the name of the chat and get, in addition to identifiers, also a title and an image. Has anyone already encountered a similar problem?
import BaseAction from "./BaseAction";
import airgram from "../airgram/airgram";
import { ChatsUnion, ChatUnion } from 'airgram';
class SearchChatsAction implements BaseAction
{
async run(name: string): Promise<any>
{
const output = await airgram.api.searchPublicChats({
query: name
});
const promises: Array<any> = [];
const result: Array<any> = [];
for (const chatId of (output.response as ChatsUnion).chatIds)
{
promises.push(
airgram.api.getChat({
chatId: chatId
}).then(output => {
result.push({
id: (output.response as ChatUnion).id,
title: (output.response as ChatUnion).title
});
})
);
}
await Promise.all(promises);
return result;
}
}
export default SearchChatsAction;
I think the issue you're facing is because of API. You should try using different API. If you check these two documentations:
searchPublicChat
searchPublicChats
The API you're using returns just chatIds but searchPublicChat will contain all the information of searched chat.

MongoDb: Accessing Collection and console log Object

I am trying to access a MongoDB Collection and I want to console.log a Object from this Collection.
I connect to my MongoDB as follows:
async function main(){
/**
* Connection URI. Update <username>, <password>, and <your-cluster-url> to reflect your cluster.
* See https://docs.mongodb.com/ecosystem/drivers/node/ for more details
*/
const uri = process.env.DB_Port;
const client = new MongoClient(uri,{ useNewUrlParser: true, useUnifiedTopology: true});
try {
// Connect to the MongoDB cluster
await client.connect();
// Make the appropriate DB calls
await listDatabases(client);
} catch (e) {
console.error(e);
} finally {
await client.close();
}
}
main().catch(console.error);
async function listDatabases(client){
databasesList = await client.db().admin().listDatabases();
console.log("Databases:");
databasesList.databases.forEach(db => console.log(` - ${db.name}`));
};
This console logs:
Databases:
- radiototem
- test
- admin
- local
Now I want to access the collection test and console log everything that is inside it. How can I achieve this?
Best regards
In order to get items from MongoDB, you first need to access the collection in which they are stored. Collections in MongoDB are basically the same as tables in SQL.
To get a collection, call the .collection() function on your DB object you get from client.db() with the name of your collection like this:
client.db().collection('test'); // This gives you the collection "test"
If you want to get items from a collection, you can use the .find() method. You can pass it a query parameter which is an object where you define, which items should be selected based on their properties.
Example, get all users named peter from the users collection:
const db = client.db();
const users = db.collection('users');
const usersNamedPeterCursor = users.find({ name: 'Peter' });
Now if you want to get all items from a collection, you can simply use the find method without the query parameter. This will return all items from the collection.
The find method returns a Cursor object which lets you interact with the returned data. You can call methods on the Cursor object like max(), min(), toArray(), each() and many more.
So, if you want to console.log every item in your collection you can do it like this:
client.db().collection('test').find().each(function(error, item) {
// console .log your item or do something else with it
});

How to Retrieve Data from Out of Axios Function to Add to Array (NEWBIE QUESTION)

I am working on building a blog API for a practice project, but am using the data from an external API. (There is no authorization required, I am using the JSON data at permission of the developer)
The idea is that the user can enter multiple topic parameters into my API. Then, I make individual requests to the external API for the requested info.
For each topic query, I would like to:
Get the appropriate data from the external API based on the params entered (using a GET request to the URL)
Add the response data to my own array that will be displayed at the end.
Check if each object already exists in the array (to avoid duplicates).
res.send the array.
My main problem I think has to do with understanding the scope and also promises in Axios. I have tried to read up on the concept of promise based requests but I can't seem to understand how to apply this to my code.
I know my code is an overall mess, but if anybody could explain how I can extract the data from the Axios function, I think it could help me get the ball rolling again.
Sorry if this is a super low-level or obvious question - I am self-taught and am still very much a newbie!~ (my code is a pretty big mess right now haha)
Here is a screenshot of the bit of code I need to fix:
router.get('/:tagQuery', function(req, res){
const tagString = req.params.tagQuery;
const tagArray = tagString.split(',');
router.get('/:tag', function(req, res){
const tagString = req.params.tag;
const tagArray = queryString.split(',');
const displayPosts = tagArray.map(function(topic){
const baseUrl = "https://info.io/api/blog/posts";
return axios
.get(baseUrl, {
params: {
tag: tag
}
})
.then(function(response) {
const responseData = response.data.posts;
if (tag === (tagArray[0])){
const responseData = response.data.posts;
displayPosts.push(responseData);
} else {
responseData.forEach(function(post){
// I will write function to check if post already exists in responseData array. Else, add to array
}); // End if/then
})
.catch(function(err) {
console.log(err.message);
}); // End Axios
}); // End Map Function
res.send(displayPosts);
});
Node.js is a single thread non-blocking, and according to your code you will respond with the result before you fetching the data.
you are using .map which will fetch n queries.
use Promise.all to fetch all the requests || Promise.allsettled.
after that inside the .then of Promise.all || promise.allsettled, map your result.
after that respond with the mapped data to the user
router.get('/:tag', function (req, res) {
const tagString = req.params.tag;
const tagArray = queryString.split(',');
const baseUrl = "https://info.io/api/blog/posts";
const topicsPromises=tagArray.map((tobic)=>{
return axios
.get(baseUrl, {
params: {
tag: tag
}
})
});
Promise.all(topicsPromises).then(topicsArr=>{
//all the data have been fetched successfully
// loop through the array and handle your business logic for each topic
//send the required data to the user using res.send()
}).catch(err=>{
// error while fetching the data
});
});
your code will be something like this.
note: read first in promise.all and how it is working.

Is there a way to instantiate a new client on server side by firebase cloud function?

I am developing an app and trying to implement news feed by getstream.io using react native and firebase.
Is there a way to generate user token by using firebase cloud function. If there is, would you please give me a pointer how i can do so? (the snippet of codes in cloud function side and client side would be super helpful..)
I have seen similar questions, only to find out no specific tutorial.. any help is appreciated!
For the cloud function side you need to create a https.onRequest endpoint that calls createUserToken like so:
const functions = require('firebase-functions');
const stream = require('getstream');
const client = stream.connect('YOUR_STREAM_KEY', 'YOUR_STREAM_SECRET', 'YOUR_STREAM_ID');
exports.getStreamToken = functions.https.onRequest((req, res) => {
const token = client.createUserToken(req.body.userId);
return { token };
});
After that, deploy with firebase deploy --only functions in the terminal & get the url for the function from your firebase dashboard.
Then you can use the url in a POST request with axios or fetch or whatever like this:
const { data } = axios({
data: {
userId: 'lukesmetham', // Pass the user id for the user you want to generate the token for here.
},
method: 'POST',
url: 'CLOUD_FUNC_URL_HERE',
});
Now, data.token will be the returned stream token and you can save it to AsyncStorage or wherever you want to store it. Are you keeping your user data in firebase/firestore or stream itself? With a bit more background I can add to the above code for you depending on your setup! 😊 Hopefully this helps!
UPDATE:
const functions = require('firebase-functions');
const stream = require('getstream');
const client = stream.connect('YOUR_STREAM_KEY', 'YOUR_STREAM_SECRET', 'YOUR_STREAM_ID');
// The onCreate listener will listen to any NEW documents created
// in the user collection and will only run when it is created for the first time.
// We then use the {userId} wildcard (you can call this whatever you like.) Which will
// be filled with the document's key at runtime through the context object below.
exports.onCreateUser = functions.firestore.document('user/{userId}').onCreate((snapshot, context) => {
// Snapshot is the newly created user data.
const { avatar, email, name } = snapshot.val();
const { userId } = context.params; // this is the wildcard from the document param above.
// you can then pass this to the createUserToken function
// and do whatever you like with it from here
const streamToken = client.createUserToken(userId);
});
Let me know if that needs clearing up, these docs are super helpful for this topic too 😊
https://firebase.google.com/docs/functions/firestore-events

Firebase Cloud Function onDelete variable param length

I have the following code
//index.js
export const deletePicture = functions.region("europe-west1").database
.ref("galleries/{galleryId}/{pictureId}")
.onDelete(pictures.deletePicture)
//pictures.js
export const deletePicture = (snap, {params: {galleryId}}) => {
console.log("Image deletion detected in the database, deleting images
from the Storage...")
const {fileName} = snap.val()
const bucket = storage.bucket()
const baseURL = `galleries/${galleryId}`
// Thumbnails
const promises = [sizes
.map(size =>
bucket.file(`${baseURL}/thumb_${size}_${fileName}`).delete())]
// Original
promises.push(bucket.file(`${baseURL}/${fileName}`).delete())
return Promise
.all(promises)
.then(() => console.log(`All versions of ${fileName} are now deleted.`))
}
In my realtime database and Storage, I have the following structure:
galleries
|_rooms
| |_roomId
| |_picture
|_foods
|_picture
Is there any way that the above mentioned onDelete Cloud Function would trigger for the deletion of either of the pictures? The difference here is that the rooms picture is one level deeper, so I think that pictureId does not match roomId/picture.
Cloud Functions has no knowledge of the meaning of your JSON. So the trigger for delete of galleries/{galleryId}/{pictureId}, really just means that this function gets triggered whenever a node at the second level under galleries gets trigged.
In the structure you show, that means that this function will trigger whenever /galleries/room/roomId or /galleries/foods/picture gets deleted. The first of these will get triggered when you delete the last picture from a room.

Resources