Firestre Subcollection - reactjs

I am trying to add INSTITUTE NAME in 1 collection. then in another collection I want to add its EMAIL ID of that institute name and email can be multiple.
What I tried
const registerRef = collection(db, 'instituteList');
const userRef = collection(db, 'usersList');
addDoc(registerRef, { institute })
.then(function (registerRef) {
addDoc(doc(userRef, registerRef.id), { email })
})
My Problem:-
I am getting this ..
Document references must have an even number of segments, but.. has 3
Please help me with this.

The firestore data model follows an alternating pattern of collections and documents. You cannot nest a collection under collection, or document under document. That's why document references always an even number of references.
You need to change your database model in order to meet this condition of firestore. Learn more about the firestore data model here

The error means that you have wrong db.collection("/one" + uid + "/three") syntax.
Also try Using 2 addDoc properties, one for adding institute name and one for emailId so your code will be:
const registerRef = collection(db, 'instituteList');
const userRef = collection(db, 'usersList');
addDoc(registerRef, {
instituteName: institute,
});
addDoc(userRef, {
emailId: email,
});

Related

Accessing the collection inside a document of a parent collection in firestore

I am looking to fetch the data of collection named users which has documents with an id of logged-in users' uid. Further, these documents contain some data and a subCollection called posts.
which looks like -
So now, I need to fetch all four(4) of these documents along with the posts collection data together so that I can display it.
My approach -
( here I fetched the document ids - middle section of image IDs)
// Fetching Firestore Users Document IDs
const [userDocs, setUserDocs] = React.useState([]);
React.useEffect(() => {
try {
const data = firestore.collection('users')
.onSnapshot(snap => {
let docIDs = [];
snap.forEach(doc => {
docIDs.push({id: doc.id});
});
setUserDocs(docIDs);
})
}
catch(err) {
console.log(err);
}
}, [])
Now, I have tried to fetch the entire data using the following way (which isn't working)
// Fetching Firestore Posts Data
const [postData, setPostData] = useState([]);
React.useEffect(() => {
try {
userDocs.map(data => {
const data = firestore.collection('users/'+currentUser.uid+'/posts')
.onSnapshot(snap => {
let documents = [];
snap.forEach(doc => {
documents.push({...doc.data(), id: doc.id});
});
setPostData(documents);
})
})
}
catch(err) {
console.log(err);
}
}, [])
Finally, I should end up with postData array which I can map on my card component to render all posted images and captions to the UI.
I am not sure if this is the right way to achieve what I am doing here, please help me correct this error and if there's a more subtle and easy way to do it please let me know. Thank You.
I have tried to fetch the entire data
Looking at the code you wrote for fetching "the entire data" (i.e. the second snippet) it seems that you don't need to link a post document to the parent user document when fetching the post documents. In other words, I understand that you want to fetch all the posts collection independently of the user documents.
Therefore you could use a Collection Group query.
If you need, for each post document returned by the Collection Group query, to get the parent user doc (for example to display the author name) you can do as explained in this SO answer, i.e. using the parent properties.

Query through all documents in a collection, and through all subcollections in firestore

I am building an app using Firebase Firestore as a BaaS.
But I am facing a problem when I try to create a feed/implement full-text-search on my app.
I want to be able to search through all the users posts, the problem is, the users posts are structured like this in the Firestore Database:
Posts(collection) -> UserID(Document) -> user posts(subcollection that holds all userID posts) -> actual posts(separate documents within that collection)
I want to loop through every user's user posts subcollection and fetch all data for the feed, and also to implement it with a full text search app like Algolia or ES.
I can loop through a specific user ID(code below), but being a beginner, I couldn't find a way to loop through all of them and fetch all of them.
firebase.firestore()
.collection('allPosts')
.doc('SPECIFIC_USER_ID') //-> Here I have to loop through all docs in that collection
.collection('userPosts')
.orderBy("creation", "asc")
.get()
.then((snapshot) => {
let posts = snapshot.docs.map(doc => {
const data = doc.data();
const id = doc.id;
return { id, ...data }
})
setUserPosts(posts)
})
}
Would love some help!
Collection Group Query
You can query in all collections named X using a collection group query.
var posts= db.collectionGroup('userPosts').orderBy('creation').limit(10);
posts.get().then((querySnapshot) => {
let posts = querySnapshot.map(doc => {
const data = doc.data();
const id = doc.id;
return { id, ...data }
})
setUserPosts(posts)
});
Source: https://firebase.google.com/docs/firestore/query-data/queries#collection-group-query
Algolia implementation
You will need to use Cloud Functions to migrate fields to a dedicated collection specifically for Algolia. Many users have found nested SubCollections to be problematic with Algolia's setup.
You do this by duplicating the user Post data as a 'source' to this new public collection, and using the Firebase Algolia Extension, you can sync it directly
exports.bakePosts= functions.firestore
.document('allPosts/{userID}/userPosts/{postID}')
.onWrite((change, context) => {
// Get an object with the current document value.
// If the document does not exist, it has been deleted.
const document = change.after.exists ? change.after.data() : null;
// Get an object with the previous document value (for update or delete)
const oldDocument = change.before.data();
if(document != null)
db.collection("posts/"+ context.params.postID).set(document);
if(document == null)
db.collection("posts/"+ context.params.postID).delete();
});
Algolia Extension:
https://firebase.google.com/products/extensions/firestore-algolia-search
You can avoid most of the above if you simply submit posts to a master collection and have the userID as the 'owner' property within the document. The above also have benefits, but more related to blog posts where users may have a "work in progress" version vs Live.
The Algolia Extension has the full guide on how to set it up and if you need to customize the extensions, the source code is also available.

How to debug this Firestore/React expression?

I don't understand the meaning of '.doc' and/or 'doc' in Firestore, and am thus unable to get my documentReference...
const getIt = () => {
setLoading(true);
const item = [];
const docRef = firebase
.firestore()
.collection("polja")
.doc("id", "==", match.params.id);
//
console.log(docRef);
//
docRef.onSnapshot((doc) => {
setItem(doc.data());
// //
setLoading(false);
});
};
You must use .doc() when you know the document ID and then the query goes as follows:
const docRef = firebase.firestore().collection("polja").doc("documentId");
But in case you are looking for documents with a specific field value, then you are looking for .where()
const docRef = firebase.firestore().collection("polja").where("id", "==", match.params.id);
This can match multiple documents where the value of that field matches the supplied value. So to control the number or results returned, use a limit clause or paginate your query.
If you use .doc() function, then the variable doc in the response is a DocumentSnapshot. You can then use doc.data() to get its data.
On the other hand, if you use .where(), it'll return FirebaseFirestore.QuerySnapshot<FirebaseFirestore.DocumentData> which contains all the documents matching the condition you had specified in the .where(). To access all the documents in that QuerySnapshot, you must access the docs property like this: snapshot.docs.
Now this will be an array of documents. You can use snapshot.size to see how many documents have matched your query.
Some practical examples to clarify:
//Collection in Firestore:
users -> {userID as documentId} -> user data in the document
//In this case you know the userID then you can should use the .doc()
const userDocRef = firebase.collection("users").doc("userId");
userDocRef.get().then((userData) => {
console.log(userData.data())
//^ this will contain data in side that document
})
//In this case, you want to find Firestore documents based on value of any field present in the document, lets say in this example if user's age is more than 15
const userDocsRef = firebase.collection("users").where("age", ">=", 15);
userDocsRef.get().then((usersData) => {
console.log(usersData.docs)
//^ this will log an array of documents which matched the condition of having the value of field age greater than or equal to 15
})

is there a solution to fetch all id in the Firestore?

i want to fecth all the id not just 888888888 and get the orders for each id
What you're describing is known as a collection group query in Firestore.
It'd looks like this:
db.collectionGroup("orders").get()
The above reads all collections called orders no matter where they are located (top-level, under an tels doc, or under any other doc.
To determine what tels doc a specific order is under, you can navigate up ref.parent.parent of the order snapshot:
db.collectionGroup("orders").get().then((querySnapshot) => {
querySnapshot.forEach((orderSnapshot) => {
const orderRef = orderSnapshot.ref;
const ordersRef = orderRef.parent;
const telRef = orderRef.parent;
console.log(refRef.id); // 8888888888
})
})

Query all documents created by a particular user

I want to return a list of documents created by a certain user, how do I? I'm using Firestore.
It's currently like this:
firestore.get({ collection: 'jobs' });
You'll need to specify the user id you want to search by. If its the current user you could do something like...
const userId = firebase.auth().currentUser.uid
then you search for all the jobs collection documents where the userId field matches you userId above...
firebase.firestore()
.collection('jobs')
.where('userId', '==', userId)
.get()
.then(collection => {
const docs = collection.docs.map(doc => doc.data());
console.log(docs)
});
I console logged the docs, but you can return them or set a field in components state, or whatever else you want to do with them.

Resources