Unable to fetch data from Firebase Firestore in react native - firebase

I am trying to GET data from Firestore but I cannot see data coming. I am building a react-native app. I am using react-native-firebase.
I also tried Transactions method from react-native-firebase documentation. But nothing is working.
Here' my code:
firebase.firestore().collection('users').doc(uid)
.get()
.then((doc)=>{
console.log(doc)
console.log(doc.data().shoppinglist)
})
.catch(e => console.log(e));
Console logging .get() gives me a Promise.
I am getting the Promise like this:
Promise {_40: 0, _65: 0, _55: null, _72: null}
_40: 0
_55: null
_65: 0
_72: null
But .then() doesn't executes as the two console.log() ain't logging anything.
Please help me out here. Quite new with Firebase.

After some digging in Firebase Documentation, I found out a solution.
Collection references and document references are two distinct types of references and let you perform different operations. For example, you could use a collection reference for querying the documents in the collection, and you could use a document reference to read or write an individual document.
Therefore, Replacing firebase.firestore().collection('users').doc(uid) with firebase.firestore().doc(`users/${uid}`) solved my problem.

For dummies in firebase like me, if you want a custom document id, you have to specify it when writing data to firestore
import firestore from '#react-native-firebase/firestore';
firestore()
.collection('Users')
.doc('ABC')
.set({
name: 'Ada Lovelace',
age: 30,
})
.then(() => {
console.log('User added!');
});
Then you can get it by
import firestore from '#react-native-firebase/firestore';
const user = await firestore().collection('Users').doc('ABC').get();
For reference: https://rnfirebase.io/firestore/usage#writing-data

Related

Access a specific part of Firestore snapshot object

I am new to firestore need to access a specific path in my snapshot from firestore(onSnapshot). I console-logged the snapshot and got the object, now I know what I want to access, but I don't know how. I tried to access it in various ways(below console log in then is a dumb way to access it, and it doesn't work) Could you please give me some clues on how to access it?
firebase.firestore()
.collection('collectionOne')
.doc(postId)
.collection('collectionTwo')
.doc(userId)
.onSnapshot((snapshot) => {
console.log(snapshot)
const data = snapshot.e._.S_.path.segments[1] //THIS, I DONT KNOW HOW
})
Object :
I'm not sure what you realy want to get but here you have an example how to get the data, id and ref of the document you are listening to:
firebase
.firestore()
.collection("collectionOne")
.doc(postId)
.collection("collectionTwo")
.doc(userId)
.onSnapshot((snapshot) => {
console.log("data", snapshot.data());
console.log("ID", snapshot.id);
console.log("reference", snapshot.ref);
});

Firebase Functions - Function not being called

I have created the following functions:
It has been deployed and is there on the firebase hosting, but it just doesn't ever get called (usage is 0)...
It should be called when a user document is changed and then update a field to null if it wasn't already null.
Can anyone see why this is not running?
exports.deleteField = functions.database.ref('/Users/{userID}')
.onUpdate((change, context) => {
const overrideTag = change.after.data().overrideTag
if (overrideTag !== null) {
const db = admin.firestore()
db.collection('Users').doc(userID).set({ overrideTag: null })
}
})
Kind Regards,
Josh
Your function is configured to trigger on changes to a node called "Users" in Realtime Database. Realtime Database doesn't have "documents". However, Firestore does have documents. If you meant to trigger when a document is changed in Firestore, you will have to write a Firestore trigger instead. It will use functions.firestore instead of functions.database.

Querying Firestore documents by Array or Map fields values in Firebase console

Here, I want to query by the value "ministoreid1" in Firebase console. But I am not able to figure out. Here, I am trying to do the query in console not using codes.
I have filed the feature request at Alex' suggestion. And the reply I received from Firebase Support:
Currently, there is no query similar to array-contains available in the Firestore Console. I can file a feature request ticket on your behalf. However, I can't guarantee anything at the moment, so please watch out for any updates on our blog or release notes for now. For the map field, you can try to filter on the console using the format: 'mapFieldName.keyName' in the field text box
So we can query for map values by 'mapFieldName.keyName'. I didn't know this before.
Here, I am trying to do the query in console not using codes.
Unfortunately, there is currently no way you can filter your documents in the Firebase console according to a value that exist in an array. As you can see, there are only the following operators:
== is equal to
> is after
>= is after and includes
< is before
<= is before and includes
But an whereArrayContains option it is not present yet. I recommend you file a feature request for that. It might be also useful for other developers.
The query that you perform in the console does't return any results because you are checking if the mini_stores_assigned is equal to ministoreid1, which obviously is not since the mini_stores_assigned property is an array and not a String so you can compare them.
For future use, Firebase has added the feature request by Ssuburat. You can now can filter your documents in the Firebase console according to a value that exist in an array.
###FILTER BLOGS BY USER.
for example if you have two collections (one to many)
/users
/blogs
blog and user has these schemes:
blog: { name,date,user:{myusername:true}}
//notice that user is a map or object and document blog has id itself wich you can use in user document and viceversa.
user:{name,lastname,blogs:{idblog1:true,idblog2:true}} //blogs is a map or object
if you want to filter by map object you can do this:
import firebase from "firebase/compat/app";
import { getFirestore } from "firebase/firestore";
const appFirebase = firebase.initializeApp(firebaseConfig);
export const dbFirebase = getFirestore(appFirebase);
const myuser= "myusername"
const q = query(collection(dbFirebase, "blogs"), where(`user.${myuser}`, "==", true));
const blogsSnapshot = await getDocs(q);
blogsSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
console.log({blogsSnapshot});

Is there a method to iterate through all documents in a collection in firestore

I'm using the firestore of firebase and I want to iterate through the whole collection. Is there something like:
db.collection('something').forEach((doc) => {
// do something
})
Yes, you can simply query the collection for all its documents using the get() method on the collection reference. A CollectionReference object subclasses Query, so you can call Query methods on it. By itself, a collection reference is essentially an unfiltered query for all of its documents.
Android: Query.get()
iOS/Swift: Query.getDocuments()
JavaScript: Query.get()
In each platform, this method is asynchronous, so you'll have to deal with the callbacks correctly.
See also the product documentation for "Get all documents in a collection".
db.collection("cities").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
});
If you know that there aren't too many docs in the collection (e.g. thousands or millions) then you can just use collectionRef.get() as described in the top-voted answer here and explained in Firebase docs.
However, in many cases, a collection can contain large numbers of documents that you can't just "get" at once, as your program's memory usage will explode. In these cases you need to implement a different traversal logic that will go through the entire collection by batches. You also need to ensure that you don’t miss any documents or process any of them multiple times.
This is why I wrote Firecode, an open-source Node.js library that solves precisely this problem. It is an extremely light, robust, well-typed, and well-documented library that provides you with configurable traverser objects that walk you through a given collection.
You can find the Github repo here and the docs site here. Also, here's a short snippet that shows you how you would traverse a users collection with Firecode.
const usersCollection = firestore().collection('users');
const traverser = createTraverser(usersCollection);
const { batchCount, docCount } = await traverser.traverse(async (batchDocs, batchIndex) => {
const batchSize = batchDocs.length;
await Promise.all(
batchDocs.map(async (doc) => {
const { email, firstName } = doc.data();
await sendEmail({ to: email, content: `Hello ${firstName}!` });
})
);
console.log(`Batch ${batchIndex} done! We emailed ${batchSize} users in this batch.`);
});
console.log(`Traversal done! We emailed ${docCount} users in ${batchCount} batches!`);

Firebase Firestore query with related document references

I'm trying to model "memberships" with Firestore. The idea is that there are companies, users and then memberships.
The memberships collection stores a reference to a company and to a user, as well as a role as a string, e..g admin or editor.
How would I query to get the users with a certain role for a company?
This is what I currently have with some basic logging.
const currentCompanyID = 'someid';
return database
.collection('memberships')
.where('company', '==', database.doc(`companies/${currentCompanyID}`))
.where('role', '==', 'admin')
.get()
.then(snap => {
snap.forEach(function(doc) {
console.log(doc.id, ' => ', doc.data());
const data = doc.data();
console.log(data.user.get());
});
})
.catch(error => {
console.error('Error fetching documents: ', error);
});
data.user.get() returns a promise to the user, but I'd have to do that for every user which seems inefficient?
What would be the best way to approach this?
Your code is close to what you want, but there are two issues:
Your where() clause can't compare a field with a document reference, because Firestore is a classic denormalized datastore. There aren't ways to strongly guarantee that one document refers to another. You'll need to store document IDs and maintain consistency yourself. (Example below).
Queries actually return a QuerySnapshot, which includes all the docs that result from a query. So you're not getting one document at a time — you'll get all the ones that match. (See code below)
So a corrected version that fits the spirit of what you want:
const currentCompanyID = '8675309';
const querySnapshot = await database
.collection('memberships')
.where('companyId', '==', currentCompanyID)
.where('role', '==', 'admin')
.get(); // <-- this promise, when awaited, pulls all matching docs
await Promise.all(querySnapshot.map(async snap => {
const data = doc.data();
const user = await database
.collection('users')
.doc(data.userId)
.get();
console.log(doc.id, ' => ', data);
console.log(user);
});
There isn't a faster way on the client side to fetch all the users that your query refers to at once -- it's part of the trouble of trying to use a denormalized store for queries that feel much more like classic relational database queries.
If this ends up being a query you run often (i.e. get users with a certain role within a specific company), you could consider storing membership information as part of the user doc instead. That way, you could query the users collection and get all the matching users in one shot.

Resources