How to get single data from collection - javascript

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.

Related

Unable to perform a Firebase query on a timestamp and receiving an empty body in response

Can someone explain to me why I am not able to perform a simple Firebase query checking for a specific timestamp in a subcollection?
The code below works if I try to retrieve the whole document, but if I add the where query it just returns a 200 response with an empty body.
I have also tried to replace db.collection with db.collectionGroup and in this case I get a 500 response with the following message Collection IDs must not contain '/'.
Here you can see how I have structured my data and my code:
try {
const reference = db.collection(`/data/10546781/history`).where("timestamp", "==", 1659559179735)
const document = await reference.get()
res.status(200).json(document.forEach(doc => {
doc.data()
console.log(doc.data())
}))
} catch(error) {
res.status(500).json(error)
console.log(error)
};
It seems you are looking for map() that creates a new array and not forEach() loop that returns nothing. Try:
const reference = db.collection(`/data/10546781/history`).where("realtimeData.timestamp", "==", 1659559179735)
const snapshot = await reference.get()
const data = snapshot.docs.map((d) => ({
id: d.id,
...d.data()
}))
res.status(200).json(data)
Additionally, you need to use the dot notation if you want to query based on a nested field.
#Dharmaraj Thanks for the help. Your answer was part of the solution. The other part concerned how my data was structured. The timestamp needed to be at the parent level of the subcollection document. So either outside the realTimeData object or the whole object needs to be flattened at the parent level.

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

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.

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;

delete a collection with document and collection again inside (firestore react native)

I am having trouble deleting on firestore
here's my delete
var chatId = route.params.number; // +639266825843
var docRef = firestore().collection('ChatRoom').doc(chatId).collection('messages');
docRef.doc(chatId).delete();
but everytime i try to delete nothing happens . There's no error at all .
this is how I set that collection
firestore().collection('ChatRoom')
.doc(id)
.collection('messages')
.add({...myMsg, createdAt:firestore.FieldValue.serverTimestamp()})
If you want to delete all the docs of the messages (sub)collection, you need to query the collection and delete each document, for example by using Promise.all() or by using a batched write (containing only deletions)
var chatId = route.params.number; // +639266825843
var colRef = firestore()
.collection('ChatRoom')
.doc(chatId)
.collection('messages');
colRef.get().then((querySnapshot) => {
Promise.all(querySnapshot.docs.map((d) => d.ref.delete()));
});
The docs property of the QuerySnapshot returns an array of QueryDocumentSnapshots.
In addition, look at how your +639266825843 document is displayed in an italic font: this means, in the console, that this document is only present as "container" of one or more sub-collection(s) but that it is not a "genuine" document. It does not exist, because you never created it, you only created docs in one of its subcollections. More detail here.

Firestore: How to correctly update multiple docs with a query

Base on this:
Can Firestore update multiple documents matching a condition, using one query?
I do below but not very sure why I am getting this error: doc.update is not a function.
let db = firebase.firestore()
db.collection('posts')
.where('uid', '==', userId)
.get()
.then((snapshots) => {
snapshots.forEach((doc) =>
doc.update({
username: username,
})
)
})
All the posts have a uid field and I am trying to change the username.
The doc itself is not the reference to the document. It's a DocumentSnapshot which has a property ref which is a DocumentReference. Try this:
let db = firebase.firestore()
db.collection('posts')
.where('uid', '==', userId)
.get()
.then(async (snapshots) => {
const updates = []
snapshots.forEach((doc) =>
updates.push(doc.ref.update({
username: username,
}))
)
await Promise.all(updates)
})
You can also use a batch write instead of pushing separate update promises.
Update: See the answer provided by Dharmaraj for a more simple, straightforward answer. I didn't consider using the .ref property as he suggests, which makes a lot of sense.
Also, my answer assumed the userID was equal to the document ID, which actually wasn't the case in this scenario. Using a query is needed when the document ID and the userID are not equal.
The querySnapshot.forEach() function passes a "QueryDocumentSnapshot" to the callback, and this QueryDocumentSnapshot does not have the update() method available.
From the docs:
"A Query refers to a Query which you can read or listen to. You can also construct refined Query objects by adding filters and ordering."
Notice the specification "read" and "listen". So if you want to write to a document, you will need to use something besides a query.
The update() method is available on DocumentReference. (If you read the quick description on the DocumentReference you'll notice it does specify 'write' as a use-case) So if we rewrote your code above to get a DocumentReference rather than a query it would look something like this:
let db = firebase.firestore();
// grabbing the DocumentReference that has a document id equal to userID
let userRef = db.collection('posts').doc(userID);
// update that document
userRef.update({username: username})
Here I'm just getting the DocumentReference using the .doc() method and storing the value in userRef. Then I can update that document with .update().
I hope this helped!

Categories

Resources