How to get the data of a user who created a document - javascript

I have two collections, one for registering properties and one for registered users.
The collection for registering properties is called listings and the collection for registered users is called users.
I access the documents inside the listings collection using the parameter listingId, which is the document ID.
I get the data from the document via the parameter I passed in:
const fetchListing = async () => {
const docRef = doc(db, 'listings', listingId)
// response
const docSnap = await getDoc(docRef)
if (docSnap.exists) {
listing = docSnap.data()
}
}
I need to get the fields (name,email, twitter, etc..) of the user who created the document.
How do I do this?
Each document has the ID of the user who creates it.

You have to do as follows:
Use the Object returned by the data() method, to get the user ID value (As explained in the doc, "this method retrieves all fields in the document as an Object").
Get the document corresponding to this user ID (exactly as you do to get the listing doc) and then, get the data of this document (again with the data() method).
const fetchListing = async () => {
const docRef = doc(db, 'listings', listingId);
const docSnap = await getDoc(docRef);
if (docSnap.exists) {
const userId = docSnap.data().user;
const userDocRef = doc(db, 'users', userId);
const userDocSnap = await userDocRef(docRef);
if (userDocSnap.exists) {
const userName = docSnap.data().name;
const userEmail = docSnap.data().email;
// ...
}
}
};
Note that a common approach for your use case in the NoSQL world is to denormalize your data in such a way that you get all the necessary data in your front-end in a minimum number of queries. Here is a "famous" post about NoSQL data-modeling approaches.
More concretely it means that in each Listing doc you would duplicate the data of its author/creator.
One side effect of this approach is that you need to keep the values in sync (i.e. the one in the User document and the ones in the Listing documents). This synchronization could be done with a Cloud Function triggered if the User doc is modified.

Related

How to query inside field value of Products in firestore

Is it possible to add onSnapshot individual fields like products, and transactions?
I want to get individual data field(products) with query.
const docRef = doc(db, 'user', user.uid);
const unsub = onSnapshot(doc(db, 'user', user.uid), (doc) => {
console.log('Current data: ', doc.data().products);
});
It's always run when bio, transactions change. But I want this function to run only when products are added or deleted.
Firestore listener are all about document change like any field of document changed then listener called, So there is two way.
Detect only when products are added or deleted on client-side for single document listener.
Put products and bio in separate document.

How to get data from document in a parent collection based on a query in a subcollection

Hey guys I try to get data from a document which has a Field value Name and a subcollection named kurzwaffensub but for my project I need to do a collectionGroup query and after that I need the Name value of each document which matches the query from the subcollection.
So let me explain.
First I need to do a collectionGroup query of the documents from the subcollection based on their two parameter kurzHersteller and kurzModell which I marked in green at the picture.
After that I get all Documents of every Subcollection which match the query.
And as you can see the blue document uid is the same uid as in the fieldvalue of every document of the subcollection.
And my goal is to get the red marked fieldvalue of the documents of the main collection after the group query of the subcollection.
But I only want to receive the Names of the documents which match the requirments of the query .
So in this Case i need the Name Felix Sturms because he has a document in his subcollection marked in yellow
which match the Search for kurzHersteller : Andere and kurzKaliber : Andere
I dont know if this is possible or if I need to structure my data in another way. Im a beginner with firebase firestore so perhabs you can help me.
const [test, setTest] = useState([]);
const HEuKA = query(kurzRef,where("kurzHersteller", "==", `${kurzHersteller}` ), where('kurzKaliber' , '==', `${kurzKaliber}`));
const handleClick = async () => {
...blablabla
...
} else if (kurzHersteller && kurzKaliber) {
const modell = await getDocs(HeuKa);
modell.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
setTest(doc.id, " => ", doc.data());
});
} else { alert('Bitte etwas eingeben')}
}
So thats the first operation after I receive the array of the documents of the subcollection which match the query , i need another operation to get the corresponding documents from the parent collection which contain the information about the Name of the users which have a document in the subcollection which match the values kurzHersteller: Andere and kurzModell: Andere of this example.
Once you get the QuerySnapshot from your collection group query, you can loop over every document and then access the parent document using .parent property present on the DocumentReference of each document. Try running the following code after your first query:
const modell = await getDocs(HeuKa);
const data = [];
for (const doc of modell.docs) {
const parentDoc = await getDoc(doc.ref.parent.parent);
const { Name } = parentDoc.data();
data.push({
...doc.data(),
Name,
});
}
Firestore reads/queries return documents from a single collection, or with collection group queries from all collections with the same name. There is no way in Firestore to include data from the parent document in the same read/query.
The two options you have are:
Read the parent document for any result you get from the subcollection.
Duplicate the necessary information from the parent document in each document in the subcollection.
While #1 is the most common option for people who are new to Firestore (and NoSQL databases in general), as you get more experienced with Firestore you'll often find yourself using #2 more often too.
I think a more robust way, where you don't depend on the structure, is to get the document from 'uid' field you have on each document you get back from the query'. Even better would be to change this field to type "reference", in which case you can just do (assuming you create a field called customerReference as a replacement for uid):
modell.forEach((doc) => {
const customerDoc = await doc.data().customerReference.get();
const name = customerDoc.data().Name;

Why I can't set state to Firebase's doc data?

I fetch data from my firestore database like thus:
const [songs, setSongs] = useState();
async function getSongs() {
const songs = collection(db, 'songs');
const songSnapshot = await getDocs(songs);
const songList = songSnapshot.docs.map(doc => doc.data());
setSongs(songList);
console.log(songList);
console.log(songs);
};
If I run this, there are two objects in the console, the first one is songList, and the second one is songs:
Why is there a difference between the two? What do I do to turn songs back into an array?
"songs" is a CollectionReference and does not contain the data. "songList" is an array which contains data from the documents returned by getDocs(). You should set songList in your state instead of songs
From the documentation,
A CollectionReference object can be used for adding documents, getting document references, and querying for documents (using query()).

Bulk Update using Batched Write of Firebase with conditions (using WHERE function)

The main goal of my system is to update the name of the user who posted on my forum if the authenticated user change or rename his or her account name.
The whole process is error-free but unfortunately, the other user who posted in the forum also updated their name.
So this is the output:
I try the following:
I use the WHERE function in Firebase to filter the post made by the user (log in user itself). I dont know why the whole process is failed.
This is the snippet code.
async updateAll(username) {
const batch = this.afs.firestore.batch();
// cUser is the USER ID
const userRef = this.afs
.collection('post', (ref) => ref.where('postedById', '==', this.cUser))
.ref.get();
(await userRef).forEach((element) => {
batch.update(element.ref, {
postedBy: username,
});
});
return batch.commit();
}
You end your query with .ref.get(). The .ref in there, actually returns the collection on which you run the query, so you end up loading the entire post collection.
You'll want to subscribe to snapshotChanges instead, or just use the regular JavaScript SDK to accomplish this (as you're not accessing the UI directly, I typically find that easier):
const userRef = firebase.firestore()
.collection('post').where('postedById', '==', this.cUser).get();
(await userRef).forEach((element) => {
batch.update(element.ref, {
postedBy: username,
});
});

How to get single data from collection

I'm using vue3 and firestore
Referring to the firestore official document, there was a way to get documents through collection. But this is the way to get all the collection data.
const citiesRef = db.collection('cities');
const snapshot = await citiesRef.get();
snapshot.forEach(doc => {
console.log(doc.id, '=>', doc.data());
});
I want to get a single document through collection.
How to get a single documemt is
const cityRef = db.collection('cities').doc('SF');
const doc = await cityRef.get();
This is a collection followed by a doc().
I can't insert a value in the doc because documemt is an auto-generated ID.
So I don't know what to do.
You have not mentioned the which document you are specifically looking for. In case you don't know the ID of the Firestore Document, you can try running a simple query using .where() like this:
const db = firebase.firestore()
db.collection("cities").where("cityName", "==", 'London').get().then(querySnapshot => {
const matchedDoc = querySnapshot.doc[0]
})
The example above finds the document where the field cityName is equal to London (both case sensitive). QuerySnapshot contains all the documents which matched your condition specified in the where() method. But in case you know there is only one matching document, as in my case I only have one doc with cityName as London, you can directly access the doc data this way: querySnashots.docs[0].data(). querySnapshot.docs is an array. [0] is the first document in it and .data() parses data from the doc. Additionally you can use querySnapshot.size to get count of documents returned from the query.

Categories

Resources