Fetching documents of sub-collections in firestore - javascript

I'm trying to fetch sub-collection documents from my firestore database.
Collection Imgs:
My current code:
const fetchHighlight =async()=>{
const Highlight = []
const HighlightDbId = await
db.collection('highlights').doc('2SCS2S0JnzngWEiYkHNk').collection('4C4kd2QnaQhcp9knexkW').get()
console.log(HighlightDbId)
}
React.useEffect(()=>
{
fetchHighlight ()
}, [])

You forgot to fetch your query at the end of your chain, and the subcollection 4C4kd2QnaQhcp9knexkW does not exist, it's the id of a document in the subcollection you're trying to access. The right subcollection ID was hBYWvZ3KN3NLLrucTpryETQZnz2.
To sum up, you could go this way:
const yourDocument = (await db.collection('highlights').doc('2SCS2S0JnzngWEiYkHNk')
.collection('hBYWvZ3KN3NLLrucTpryETQZnz2').doc('YOUR_DOC_ID').get()).data()
or this way:
const yourDocument = (await db.collection('highlights/2SCS2S0JnzngWEiYkHNk/hBYWvZ3KN3NLLrucTpryETQZnz2')
.doc('YOUR_DOC_ID').get()).data()
Edit
If you want to fetch only the first document of the subcollection you can go this way:
const yourDocument = (await db.collection('highlights').doc('2SCS2S0JnzngWEiYkHNk')
.collection('hBYWvZ3KN3NLLrucTpryETQZnz2') // subcollection ref
.orderBy("createdAt", "asc") // index
.limit(1) // limit the size of your response
.get()) // send the request and wait for it (you could also use '.then()' here)
.docs[0] // get the first doc of the array
.data() // retrieve the doc's data use `.id` instead if you want its id
And if you want to get the first subcollection of a doc you should go this way with the listCollections method:
const subcollectionId = (await db
.doc('highlights/2SCS2S0JnzngWEiYkHNk')
.listCollections())[0] // retrieve the first subcollection `.id`
Note that this only works with the node.js library, if you're attempting to do your query fore the front-end, it will fail. Then you should simply put a reference of your subcollection inside your parent doc by an update when creating your subcollection in the first place:
// const HighlightDbId = creating you subcollection
db.collection('highlights').doc('2SCS2S0JnzngWEiYkHNk').update({
subcollection: HighlightDbId
});
And simply retrieve the field subcollection when you need to fetch data from its subcollection.

I fixed this problem by adding the last doc :
db.collection('highlights').doc('2SCS2S0JnzngWEiYkHNk').collection('4C4kd2QnaQhcp9knexkW').doc('XXXXXXXX').get()

Related

How to access array in Firestore v9

Articles I've read/tried before:
Firestore search array contains for multiple values
Performing a complex query with firestore v9
Firestore collection to array of objects with Firebase v9
FirebaseError: Expected type 'Tc', but it was: a custom Ac object,
https://softauthor.com/firebase-firestore-get-document-by-id/
I have a Firestore that looks like this
The current feature I'm trying to implement is a block list. Whenever you go to the person's profile, you click block, and the person doing the blocking's UID is stored as the doc id and the blocked user's id is added to the "blockedUserId" array
The home page displays all the posts and I've been trying to filter the displayed posts to not include posts from any of the users in that "blockedUserId" array
How do I go about doing this correctly?
Here is the attempted code
query(
collection(getFirestore(fireApp), "posts"),
orderBy("uid"),
where(
"uid",
"not-in",
doc(getFirestore(fireApp), "block", "vXLCRjlhOVW6oFOJvtmML6OolKA2")
)
Firestore queries can only filter on values in the document itself, and values you explicitly pass in to the query. Your doc(getFirestore(fireApp), "block", "vXLCRjlhOVW6oFOJvtmML6OolKA2") creates a DocumentReference, so the query returns documents from posts that don't contain that document reference.
What you want to do instead is:
Load the blocked UIDs
Pass them to the query
So in code:
const myRef = doc(getFirestore(fireApp), "block", "vXLCRjlhOVW6oFOJvtmML6OolKA2");
const myDoc = await getDoc(myRef);
const blocked = myDoc.data().blockedUserId;
const q = query(
collection(getFirestore(fireApp), "posts"),
orderBy("uid"),
where(
"uid",
"not-in",
blocked
)
)
// TODO: call getDocs or onSnapshot on q

Get a DocumentReference without providing an ID in Firebase 9 web version Javascript SDK

I'm trying to commit a batch write using firebase 9 modular sdk. This operation includes creating a post document, ideally with an auto generated id.
const batch = writeBatch(db)
const postRef = doc(db, 'posts') // this fails, must pass and id
const threadRef = doc(db, 'threads', post.threadId)
batch.set(postRef, post)
batch.update(threadRef,
'posts', arrayUnion(postRef.id),
'contributors', arrayUnion(state.authId))
await batch.commit()
In Firebase 8 it's possible to obtain a document reference with a random generated id using with the following code.
firebase.firestore().collection(nameOfTheCollection).doc()
I'm trying to accomplish the same thing using Firebase 9 modular sdk, but I can't find any method to do this.
Is it possible to get a document reference with a random generated id without creating the document first with Firebase 9?
You can use the doc() function and pass a CollectionReference as first parameter without any path segments as shown below:
import { doc, collection } from "firebase/firestore";
const docRef = doc(collection(db, "colName")); // Don't specify an ID yourself
console.log(`New Document ID: ${docRef.id}`);

Firebase Query, get multiple documents from a single collection where each doc.id is equal to the id in a seperate list

I am building a simple react-native app using firebase, in which users can create posts, see lists of other users posts, and posts can be saved as a "saved posts" as a sub-collection within my users collection.
I am new to react-native and firebase so this is just for educational purposes.
I am getting stuck on querying the posts for my 'saved' list. Currently, when a user clicks the 'save' button, a sub-collection of 'saved posts' is added to (or created) of the post id. I do not want to rewrite the entire post data to the users saved list, only to create a reference to the post via the post id.
I am able to save the list, but have not been able to query firestore for the documents associated with each post id.
Currently I can query based on the users id to retrieve the list of their own posts, as the authorID matches the user uid, and I thought getting the saved posts would be similar.
Here is my code for getting a users own list of posts:
userId is a single string representing user.uid
const getUserPosts = async (userId) => {
const snapshot = await firebase
.firestore()
.collection('posts')
.where('authorID', '==', userId)
.get();
let data = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
return data;
};
This function is exported and then wrapped in a try catch statement within the component.
The difference between the above and getting the users list of saved posts is that I have multiple different "postId's" which I need to input (vs a single userID), but the .get() method will not accept an array for the first argument, it requires a single string.
To quickly summarize I need a method or function in which I can take an array of postId's and query my posts collection to return those posts in which the doc.id matches the postId's provided.
I apologize if this is unclear or confusing, I am getting a bit lost on this one.
Any suggestions would be very welcomed.
Thank you so much for your time!
You can do a query for multiple document IDs at once using an "in" query and using FieldPath.documentId():
const array = [...];
const snapshot = await firebase
.firestore()
.collection('posts')
.where(firebase.firestore.FieldPath.documentId(), 'in', array)
.get();
But this only works if the array is of less then 10 items long (Firestore limitation). If you need more, you'll have to either batch the IDs, into smaller arrays and perform multiple queries, or simply iterate the IDs, and get() each document individually (which is just fine, really, don't worry about performance on that).
It's working :)
Big Thank you to Doug Stevenson for your help!!
Here is the function:
postedId is an array of id's referring to the id of saved posts from the 'posts' collection
export const getSaveData = async (postedId) => {
const array = [postedId];
const snapshot = await db.collection('posts').get();
const data = snapshot.docs.map((doc) => ({ postedId: doc.id,
...doc.data() }));
return data;
};

How to create document with subcollection

I can't find how to create a new document without any fields, but one subcollection - messages (and this message collection would have some fields).
This is what I want to do. But I don't want to create subcollection in document which already exist. I want to create new document and subcollection in it.
Honestly I stopped on that :
let chatRef = db.collection("chat_event").add({
})
This answer will greatly help.
let chatRef = db
.collection("chat_event").document("chat1")
.collection("messages").document("message1");
If you don't want to hardcode the parent document's id or if you want a firestore generated id. Then get the id first from firestore's createId() function.
let chatEventId = db.createId();
let chatRef = db
.collection("chat_event").document(chatEventId)
.collection("messages").document("message1");
You could still use auto-generated id for the subcollection's document:
let chatEventId = db.createId();
let messageId = db.createId();
let chatRef = db
.collection("chat_event").document(chatEventId)
.collection("messages").document(messageId);
Note that firestore's autogenerated IDs are entirely random and consequently the documents are not stored in any chronological order. If you will in anyway need some ordering, you could add timestamps to those documents either when you insert data or you update the document with the timestamp info.
docRef.update({
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
With that, you can order chronologically both in the console and in your own queries.
Check out this answer for more information on auto-generating IDs

Get document id from Firestore after fetching document

How can I get the document id of a firestore document after successfully fetching the document. I am fetching user data from firestore collections like this
const ref = await db.collection('users').where('phone', '==', phone)
.where('password', '==', password).get();
I have a valid document after executing this query.
const data = ref.docs[0].data();
How can I get the auto generated document id? I tried data.id and data.path, it is returning undefined.
How can I access the auto generated id?
In my code, it was actually trying to get the data id, instead of document id
i got the document id by adding const docRefId = ref.docs[0].id;
In addition to Sony's answer, you can get the document reference as well:
const docRefId = ref.docs[0].ref;

Categories