How to get array from firebase firestore - javascript

I'm doing a react project for download movies . In this project user can like to movie and add to watchlist. I need to get array of like and store it on browser local storage . I need to know how to get array from firestore .
This is path of array I need to get.
users > {user id} > likes
This is what I tried.
firebase
.firestore()
.collection("users")
.doc(firebase.auth().currentUser.uid)
.collection("likes")
.get()
.then((likes) => {
console.log(likes)
});

.collection("likes") likes is a field not a collection so to get likes field you have to read whole document.

Try like this
firebase
.firestore()
.collection("users")
.doc(firebase.auth().currentUser.uid)
.get()
.then((user_doc) => {
console.log(user_doc.data())
});

Related

How do I fetch user information to display in a feed of posts using firebase storage solutions?

I'm building a forum-style application where users post content that displays on a global feed. I want to display information about the user in posts (photoURL, displayName) similar to Twitter.
I have firebase v9 using the authentication and firestore for the posts. The reason I want to reference the auth is that I can catch changes to the user's information as it happens, this way the feed is up to date.
I save the user's unique ID with the post so I am able to reference who to display. I can successfully reference the post title and description with doc.title & doc.description however I get stuck when retrieving user information. I'm trying doc.UserID.displayName for the display name but I know this is incorrect. I can't find anything in the docs for this specific use case, is this something that I can do with just firestore and auth?
Do I need to create a reference to the auth storage with doc.UserID?
Here is the code:
// add a new post
addPostForm.addEventListener('submit', (e) => {
e.preventDefault();
onAuthStateChanged(auth, (user) => {
const colRef = collection(db, 'Posts');
console.log(hiddenURL.value);
addDoc(colRef, {
UserID: user.uid,
beatURL: hiddenURL.value,
title: addPostForm.postTitle.value,
description: addPostForm.postDescription.value,
})
.then(() => {
console.log("Document written with ID: ", doc.id);
addPostModal.classList.remove('open');
addPostForm.querySelector('.error').textContent = "";
})
.catch(error => {
addPostForm.querySelector('.error').textContent = error.message;
alert(error);
})
})
});
export const initApp = async () => {
initFirebaseAuth;
const posts = await collection(db, 'Posts');
// render data to the page
return renderPosts(posts);
};
const renderPosts = (posts) => {
const main = document.getElementById("feed");
onSnapshot(posts, (snapshot) => {
let cardsArray = []
snapshot.docs.forEach((doc, user) => {
cardsArray.push({ ...doc.data(), id: doc.id })
name.textContent = `${doc.UserID.displayName}`; // users display name
avatar.src = doc.UserID.photoURL; //user's image
description.textContent = `${post.description}`;
title.textContent = `${post.title}`;
});
console.log(cardsArray);
});
};
There are two cases and approaches at first sight:
1. Your users profiles are only available in the Auth Service
In this case, via the JS SDK, a user X cannot "query" the Auth profile of a user Y.
This means that you need to save the author's displayName together with the author uid when the post is created.
2. Your users profiles are also available in a users collection (a common pattern)
In this case, when you display a post, you could fetch the user's document to get the author's displayName.
However, in the NoSQL world, you should not be afraid to duplicate data and denormalize your data model. When designing your data-model you should think about it from a query perspective, trying to minimize the number of queries for a given screen/use case. So approach #1 is recommended, even if you maintain a user's collection.
In case of changes in the user's profile, in order to synchronyse the post documents and user's data a common approach is to use a set of Cloud Functions (which are executed in the back-end) to update the post documents. The link between the posts and the users profile being the user's uid.

Fetching documents in a subcollection of a cloud firestore database does not return any data

I am using cloud firestore database to store documents for user inside a next.js application, the collection path is as follows
collection "userDocs"
└─ document "userEmail"
└─ collection "docs"
└─ document "documentObject"
I was using Firebase v9 SDK and I downgraded to firebase v8 and I am still facing the same issue.
This code snippet is where I add a new document to the database which is done and reflects successfully in the Firebase console
db.collection("userDocs").doc(session.user.email).collection("docs").add({
fileName: input,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
});
When trying to fetch documents from the database I tried the following approaches:
1. Using react-firebase-hooks
const [snapshot] = useCollectionOnce(
db
.collection("userDocs")
.doc(session?.user.email)
.collection("docs")
.orderBy("timestamp", "desc")
);
2. Using Firebase query
useEffect(() => {
var query = db.collection("userDocs");
query.get().then((querySnapshot) => {
querySnapshot.forEach((document) => {
document.ref
.collection("docs")
.get()
.then((querySnapshot) => {
console.log(querySnapshot);
});
});
});
});
This is how I tried to achieve it using firebase v9
import {
collection,
query,
orderBy,
serverTimestamp,
setDoc,
doc,
collectionGroup,
onSnapshot,
getDocs,
} from "firebase/firestore";
useEffect(async () => {
const docRef = query(
collection(db, "UserDocs", session?.user.email, "Docs"),
orderBy("timestamp", "desc")
);
const docSnap = await getDocs(docRef);
const allDocs = docSnap.forEach((doc) => {
console.log(`Document ${doc.id} contains ${JSON.stringify(doc.data())}`);
});
}, []);
I managed to get around this using the following approach:
1- I restructured my database to contain "docs" collection which holds inside a document object that has the following attributes {email, fileName, timestamp} instead of creating a subcollection.
I created the following method to fetch data and map it into a state array to be able to render it
const getDocuments = async () => {
await db
.collection("docs")
.where("email", "==", session?.user.email)
.orderBy("timestamp", "desc")
.get()
.then((res) => {
setUserDocs(res.docs);
})
.catch((error) => {
console.log(error);
});
};
I am still not quite sure why exactly did this attempt work rather than all other trials, but I managed to get things working so far so that's the most important thing for the time being.
The problem was that you were not structuring your data correctly. As shown on the Firebase official documentation Choose a data structure,
when you structure your data in Cloud Firestore, you have a few different options:
Documents
Multiple collections
Subcollections within documents
Consider the advantages of each option as they relate to your use case
Therefore, from the code you've shared in your answer, the structure you're using is Nested data in documents.
I've got a little bit lost on your first approach, but since you've finally got it working, the advice is to structure your data according to what is stated in the documentation and what fits your necessity.
See also
https://firebase.google.com/docs/firestore

Issue saving user object to Firebase realtime database

Im using the firebase authentication function which returns a user object as follows:
auth()
.createUserWithEmailAndPassword(email, password)
.then(user => {
Im then trying to save this user object to the Firebase database like so
database()
.ref('profiles/users/' + user.user.uid)
.set({
myUserObj: user,
})
However firebase database is returning an error 'Cannot read property 'code' of undefined' FULL CODE BELOW
auth()
.createUserWithEmailAndPassword(email, password)
.then(user => {
console.log(user.user);
database()
.ref('profiles/users/' + user.user.uid)
.set({
myUserObj: user,
})
.catch(err =>
console.log(err.message),
);
})
Firebase Realtime Database can only store valid JSON objects. The UserCredential object contains many methods, which makes it not a valid JSON object.
You could give it a try to save it with:
database()
.ref('profiles/users/' + user.user.uid)
.set({
myUserObj: JSON.parse(JSON.stringify(user)),
})
If this doesn't work, you'll have to explicitly name the properties that you want to save.

Firebase Database - Login

I have a register page working well, this is my database.
enter image description here
Each one has an ID and you Login using Username and password,
And I am using this code, to verify if the username is in database.
ref.child("accounts").orderByChild("lowerun").equalTo(username.toLowerCase()).once("value",snapshot => {
if (snapshot.exists()){
const userData = snapshot.val();
console.log(userData)
}
})
But how do I get the password for the username?
Dudis! Welcome to SO! It looks like you're using Firebase Realtime Database? I think you're using the database API incorrectly if you're trying to fetch user number 1 in your accounts. Here is something you could try:
database
.ref("main/accounts")
.child(userId)
.once("value", snapshot => {
// check if snapshot exists
// log your snapshot.val()
})
Also, as Doug suggested, I would strongly suggest using Firebase Authentication.

Auth0: fetch data of group of users

I have an application with Auth0 and graphQl.
I use dataloaders to batching requests to DB. https://github.com/graphql/dataloader
For example, fetching data from DB looks like:
// Booking is Mongoose model
new DataLoader(
bookingIds => Booking.find({ _id: { $in: bookingIds } }),
);
And now I need to fetch data about group of users. Of course, I can write
// getUser is ManagementClient.getUser from 'auth0' package
new DataLoader(
userIds => Promise.all(
userIds.map(
id => getUser({ id }),
),
),
)
This solution is slowly. Can I get data of collection of users by one request?
I work with the Auth0 Community team. You can retrieve users with the GET users endpoint from the management console. Give it a look when you get a chance. Thanks!

Categories

Resources