I'm trying to learn a bit of firebase.
I've made a small site where i can add and delete data from firestore as well as some log in and out functions.
I want to move forward by instead of displaying the results in the console showing them on the screen.
below is a snippet of my code, everything works okay i have imported everything correctly and it all shows in the console without errors but I cannot figure out how to get this to the HTML file in order to display it in the browser.
index.js file
//collection ref
const colRef = collection(db, 'books')
//queries
const q = query(colRef, orderBy('createdAt'))
booksDisplay = document.getElementsByClassName('books')
//real time collection data
onSnapshot(q, (snapshot)=>{
let books = []
snapshot.docs.forEach((doc)=>{
books.push({...doc.data(), id: doc.id})
})
})
booksDisplay.innerHTML='<p>'+books+'</p>'
index.html
<h2>Display Books</h2>
<div class="books"></div>
Related
Recently I've built a chat app using react + firebase but there's something that doesn't work quite right.
I'm able to send messages and have them stored in the firebase database. Now here's the problem: it only shows the first 25 messages that got stored.
Here's the part of the code that's problematic:
const messagesRef = firestore.collection("messages");
const query = messagesRef.orderBy("createdAt").limit(25);
Is there a way to start at the bottom from the last 25 message? Using "desc" doesn't work either because it displays the data starting from the last message at the top and I want the exact opposite.
firebase has a .limitToLast() function that you can chain on to your .collection()
const query = messagesRef.orderBy("createdAt").limitToLast(25);
LimitToLast Docs
LimitToLast filtering docs
For instance:
const query = messagesRef.orderBy("createdAt", "desc").limit(25);
Here you have more info: https://firebase.google.com/docs/firestore/query-data/order-limit-data#node.js
I would like to get the last key (the latest message) from my realtime database but not sure how this can be achieved.
I see from this link i need to get Last child of my firebase databse that I can use orderByKey().limitToLast(1) to get this but it looks like I need to specify the complete ref in order to achieve this. Is that correct? Or is it possible if I can orderByKey().limitToLast(1) on the val()? Or is there another way I can achieve this?
Here is my messages structure in the database:
I have a timestamp child under each key as shown above which I thought I could query in order to extract the latest key but I really don't know how to do this. Can someone please help? Below is my code so far:
database().ref(`messages/`).once(`value`, snapshot => {
if(snapshot.exists()) {
snapshot.forEach(function (childSnapshot) {
if(childSnapshot.key.includes(auth().currentUser.uid)) {
console.log("show me the key: "+childSnapshot.key)
//not working
console.log("show last message: "+ JSON.stringify(childSnapshot.val().orderbyKey().limitToLast(1)))
}
})
}
})
console.log(JSON.stringify(messages)) => [{"-MfqYBzbusp1Cljgxpan":{"unreadMessage":true,"user":{"name":"Mike","avatar":"xxxxxx","_id":"tFhmw5oQoPhk8nF2sx5rE5BFqw93"},"timestamp":1627634061437,"senderId":"tFhmw5oQoPhk8nF2sx5rE5BFqw93","notification":{"body":"Hey","title":"Project","imageUrl":"./assets/xxxxx.png"},"text":"Hey"}}]
console.log(JSON.stringify(unreadMsgs)) => []
Firebase Realtime Database queries work on a flat list of nodes. So if you have a specific path /messages/nodeid already, you can find the latest message under that, but you can't find the latest message across all of /messages.
Reading all messages from all chatrooms, just to find the latest message for each chatroom this user is in is really wasteful though. As you add more users to the app, you're driving up the bandwidth cost for them, and for yourself too.
I recommend keeping a separate node where you track the chat rooms for each user, as explained in my answer on Best way to manage Chat channels in Firebase. With such a node you can then easily determine just the chat rooms for the current user, and then load the latest message for each of them with something like:
database().ref(`user_chatrooms/${auth().currentUser.uid}`).once(`value`, indexSnapshot => {
indexSnapshot.forEach((indexSnapshotChild) => {
let chatroomId = indexSnapshotChild.key;
let query = database().ref(`messages/${chatroomId}`).orderByChild("timestamp").limitToLast(1)
query.once(`value`, (msgSnapshot) => {
console.log(`Last message in ${chatroomId} was ${msgSnapshot.val().text}`);
})
}
})
The orderByKey and limitToLast methods exists on a DatabaseReference and not on the value you fetch from the snapshot fetched earlier. It seems the parent key for all messages is of format userId1userId2. If you know this combination then you run your query this way.
const uidsKey = "uid1" + "uid2"
const query = database().ref(`messages/${uidsKey}`).orderByChild("timestamp").limitToLast(1)
query.once("value").then((snapshot) => {
console.log(snapshot.val())
})
But it seems you are trying to get UIDs of others users who have chats with user1 and trying to real all nodes first. I won't recommend doing that as that might have issues with security rules and so on. Instead if you keep list of those UIDs somewhere else, it'll be better. But if you want to keep what you have right now, try this:
const userUID = auth().currentUser.uid
database().ref("messages/").once("value").then(async (msgSnapshot) => {
const keys = Object.keys(msgSnapshot.val() || {})
const userChatKeys = keys.filter(k => k.includes(userUID))
//const otherUserIDs = userChatKeys.map(k => k.replace(userUID, ""))
//userChatKeys will be chat IDs where current user is included
//now follow the same steps mentioned in first code snippet
const queries = userChatKeys.map(chat => database().ref(`messages/${chat}`).orderByChild("timestamp").limitToLast(1).once("value"))
const lastMessagesSnap = await Promise.all(queries)
const messages = lastMessagesSnap.map(m => Object.values(m.val())[0]))
console.log(`messages: ${messages}`)
const unreadMsgs = messages.filter((msg) => msg.unreadMessage === true)
console.log(unreadMsgs.length)
})
This will logs last message from each of user's chat.
I have a shopping cart app I developed using React, I have been working on a feature which scrapes data from a grocery store using puppeteer. The problem I am having is that im not sure of how to go about and share the data from my puppeter.js file and implement the data, and display it in my react app.
Any help is appreciated.
You need to get the data and save it to the local folder in a json format. Then you can use it in your react app. For example
const puppeteer = require("puppeteer")
const fs = require("fs")
async function scrapeData () {
const browser = await puppeteer.launch()
const [page] = await browser.pages()
/*
I dont know how your data is stored or what data you want to get so i cant
implement
getting the data here. Assume that i got it and stored in a variable named
'theData'
*/
fs.writeFile("theData.json", JSON.stringify(theData), () => {
console.log("The data saved to the file named theData.json")
})
}
scrapeData()
Then you can use fs.readFile() method to read and use it in your react app.
in our app each time users are posting 2 pictures that are being saved to different folders and being pulled to display in another page. Sometimes the images are displaying out of order due to data being pulled I'm assuming.
I want to display the images that are taken the same day next to one another in descending order.
I see in documentations that are being mentioned that StorageMetadata to get metadata from the images but when I click my Other Metadata in firebase storage it shows nothing.
There is orderBy('desc') but that is for Firebase. I want to display images in descending order and if the user skips posting an image then it would skip and go to the next line.
This is what I have so far. How can I pull the images in descending order?
const getFrontImage = async () => {
const imageRefs = await firebase.storage().ref().child(user + '/FrontPic/').listAll();
const urls = await Promise.all(imageRefs.items.map((ref) => ref.getDownloadURL()));
// this is to get the metadata but there is a list of images in that folder.
// if I user StorageMetadata() on .listAll() it gives an error since it's not an object.
const date = await firebase.storage().ref().child(user + '/FrontPic/').StorageMetadata();
console.log("<><><> This is the metadata " + date);
setFrontImage(urls);
}
I have written a Firebase cloud function in which I want to get every users internal collection called 'numbers' and read each document out of that collection to do some comparisons.
Any idea how to do this?
I am pretty new to firebase and for some reason the database navigation commands are just not sticking with me very well.
I have tried a handful of commands with no success
const snapshot = functions.database.collection('users').collection('numbers').get()
let sfRef = db.collection('users');
sfRef.getCollections().then(collections => {
collections.forEach(collection => {
console.log('Found subcollection with id:', collection.id);
});
});
Here is a loose cloud code infastructure
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
export const prize1 = functions.pubsub.schedule('every 5 minutes').onRun((context) => {
const users = functions.database.ref('/users/numbers')
console.log("")
return null;
});
I feel like I have a good idea of how to do it, but the syntax is holding me back.
The collection of users. Go through each document in here, i.e. each user.
In each user go to the collection called numbers.
In the collection called numbers go through each document and find the numbers field to do logic/comparisons with.
Hopefully this can help you understand the way my database is ordered.
You could try it like this:
let usersRef = db.collection('users');
let allUsers = usersRef.get();
.then(userSnapshot => {
userSnapshot.forEach(userDoc => {
userDoc.ref.collection('numbers').get().then(numSnapshot => {
numSnapshot.forEach(numDoc => {
console.log(numDoc.data().numbers);
// here you got your numbers document with the numbers field
});
});
});
})
.catch((error) => {
console.log("Error getting document: ", error);
});
For more information you can look here and here.
You can't use functions for accessing the database. What you've defined as functions is for building triggers that respond to events. If you want to get data from Cloud Firestore, you should be using the Firebase Admin SDK via your admin instead. It might also help if you look through the official samples.
I will also point out that your code samples appear to be split between accessing Cloud Firestore and Realtime Database, which are different database products. Your screenshot shows Firestore, so ignore any APIs for Realtime Database.