I am trying to get a post title from firestore but somehow I could not figure out how that could be done using async await.
async getVideo(id) {
var self = this;
const ref = this.$fire.firestore
.collection("posts")
.where("ytid", "==", id)
.orderBy("createdAt", "desc");
try {
let post = await ref.get();
console.log(post.data());
} catch (e) {
console.log(e);
}
}
I tried to console log post.data() but it says post.data() is not a function.
Any help would be appreciated.
When you call ref.get(), you will get a QuerySnapshot object. This object contains zero or more DocumentSnapshot objects that contain the data from the query results. QuerySnapshot does not have a method called data(). You will have to iterate the documents using the provided API to get the DocumentSnapshots:
const qsnapshot = await ref.get();
qsnapshot.forEach(doc => {
const data = doc.data();
console.log(data);
})
You are retrieving multiple documents, so post will be a snapshot of documents which does not have a data() method.
You'll need to iterate through the snapshot to access the individual documents.
See https://firebase.google.com/docs/firestore/query-data/get-data#get_multiple_documents_from_a_collection for a quick guide or https://googleapis.dev/nodejs/firestore/latest/QuerySnapshot.html for a full reference of the QuerySnapshot type.
Related
I have a collection where it contains a couple of docs which all contains a id-field individual. But i can't figuere out how I can delete a specific document based on my query.
I have tried with this:
const deleteItem = async(item) => {
const d = query(collection(db, 'allTasks'), where('id', '==', item.id));
const docSnap = await getDocs(d);
docSnap.forEach((doc) => {
console.log(doc.data())
deleteDoc(doc.data());
});
}
But i get the error: [Unhandled promise rejection: TypeError: t is not an Object. (evaluating '"_delegate" in t')]
Is this the wrong way or should i use batch?
The console.log shows the right item that i have clicked delete on
The deleteDoc() function take DocumentReference as parameter and not the document data.
docSnap.forEach((doc) => {
deleteDoc(doc.ref); // and not doc.data()
});
Additionally, it might be a good idea to use a batch to delete documents to ensure they are all delete or none.
I am trying to update a user's firestore doc from a Firebase Function using a query, and having issues getting it to work. My Function code is the following:
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
/**
* A webhook handler function for the relevant Stripe events.
*/
// Here would be the function that calls updatePlan and passes it the customer email,
// I've omitted it to simplify the snippet
const updatePlan = async (customerEmail) => {
await admin.firestore()
.collection('users').where('email', '==', customerEmail).get()
.then((doc) => {
const ref = doc.ref;
ref.update({ 'purchasedTemplateOne': true });
});
};
I'm getting the following error in the firebase logs when the query is run:
Exception from a finished function: TypeError: Cannot read properties of undefined (reading 'update')
Any help regarding what I may be doing wrong or suggestions on how I could achieve this would be greatly appreciated, Thank you in advance!
Update:
I was able to solve my problem with more understanding of Firestore Queries:
const updatePlan = (customerEmail) => {
const customerQuery = admin.firestore().collection("users").where("email", "==", customerEmail)
customerQuery.get().then(querySnapshot => {
if (!querySnapshot.empty) {
// Get just the one customer/user document
const snapshot = querySnapshot.docs[0]
// Reference of customer/user doc
const documentRef = snapshot.ref
documentRef.update({ 'purchasedTemplateOne': true })
functions.logger.log("User Document Updated:", documentRef);
}
else {
functions.logger.log("User Document Does Not Exist");
}
})
};
The error message is telling you that doc.ref is undefined. There is no property ref on the object doc.
This is probably because you misunderstand the object that results from a Firestore query. Even if you are expecting a single document, a filtered query can return zero or more documents. Those documents are always represented in an object of type QuerySnapshot. That's what doc actually is - a QuerySnapshot - so you need to treat it as such.
Perhaps you should check the size of the result set before you access the docs array to see what's returned by the query. This is covered in the documentation.
yeap, if read a title you can think that it is simple action via collection - but no -> in you we have a button "Add collection": not clear how to add this collection via code or how to receive these created collections.
Please take a look at the structure of BD in the attachment:
.
I can receive ID of a document, but not clear how to receive collection(s)/data of these collections. here i just receive the main ID, not "1" collection and his data:
const listCollections = [];
await db
.collection(table)
.get()
.then((snapshot) => {
snapshot.docs.forEach((doc) => {
debugger
const dataCollectionObject = doc.data();
dataCollectionObject.id = doc.id;
listCollections.push(dataCollectionObject);
});
});
When you receive a document, you need another query to inspect its sub-collections.
Also, I suggest not mixing async/await with then.
A basic approach
const rootSnapshot = await db.collection(table).get();
const promises = rootSnapshot.docs.map(rootDoc => rootDoc.ref.collection("1").get());
const childrenDoc = await Promise.all(promises);
Using collection group queries
see the doc
const childrenDoc = await db.collectionGroup("1").get();
If you do not know the sub-collection name
Bad luck! With Firestore you are required to know the name of your collections. You could for exemple store it in another data member:
document {
someField: ...
collectionIds: ["1", "2"] // store the sub-collection ids
"1" // a sub-collection
"2" // another sub-collection
}
Then when you retrieve such a document, inspect its data and loop on collectionIds to query deeper.
I've a collection called users, inside each document's users have a collection called monthlies and I want get it.
This is the structure:
At now, I tried get it using:
var getUsers = async function() {
var db = firebase.firestore()
var users = await firebase
.firestore()
.collection("users")
.get();
return users
}
var getMonthlyByUserId = async function () {
var users = await getUsers()
users.forEach(element => {
var monthlies = element.collection('monthlies').get()
console.log(monthlies.docs.map(doc => doc.data()))
})
}
But it prints nothing. The goal is iterate of all documents' monthlies of the collection.
In addition to the problem that Doug pointed out (you need to use the ref property of the QueryDocumentSnapshot), you need to take into account that the get() method is asynchronous.
So doing
users.forEach(snapshot => {
var monthlies = snapshot.ref.collection('monthlies').get()
console.log(monthlies.docs.map(doc => doc.data()))
})
will not work.
If you cannot use a collection group query (for example, let's imagine that your getUsers() function only returns a subset of all the users, e.g. all users of a given country) you could use Promise.all() as follows:
var getMonthlyByUserId = async function () {
const users = await getUsers();
const promises = [];
users.forEach(snapshot => {
promises.push(snapshot.ref.collection('monthlies').get());
});
const monthlies = await Promise.all(promises);
monthlies.forEach(snapshotArray => {
console.log(snapshotArray.docs.map(doc => doc.data()));
});
}
OR you could use the technique described in this article on how to use async/await inside a forEach().
In your code, element is a QueryDocumentSnapshot type object. It doesn't have a method called collection(), so I would expect your code will crash with an error in the log.
If you want to reference a subcollection organized under a document represented by QueryDocumentSnapshot, you should build upon its ref property:
users.forEach(snapshot => {
var monthlies = snapshot.ref.collection('monthlies').get()
console.log(monthlies.docs.map(doc => doc.data()))
})
Alternatively, if you just want to query all documents in all subcollections called "monthly", you can simplify that with a single collection group query.
When I have fetched places that we can see in screenshot below, I need get their data, but it's reference to data, I can get the data without additional request like place.ref.data()? If I have 30 places, should I make 30 requests, really? I use react native and the ref object has type DocumentReference https://rnfirebase.io/docs/v3.1.x/firestore/reference/DocumentReference
You need to create your own populate method.
Here's one example I made where my collection eventSchedule has references to events, then I have the array of events and I want to get the events from each eventSchedule... That's how I did:
...
const docRef = db.collection("eventSchedule").doc(dayName);
try {
const doc = await docRef.get();
if (doc && doc.exists) {
const eventSchedule = doc.data();
if (eventSchedule.activeEvents) {
const activeEventsRefs = eventSchedule.activeEvents;
eventSchedule.activeEvents = [];
await activeEventsRefs.reduce(
async (promise: any, event: any) => {
await promise;
const childDoc = await event.get();
if (childDoc) {
eventSchedule.activeEvents.push(childDoc.data());
}
},
Promise.resolve()
);
}
} else {
logMessage += `No docs found for eventSchedule for today - ${dayName}`;
}
} catch (error) {
logMessage += `Error getting document ${JSON.stringify(error)}`;
}
So I used reducer to handle the promises. It works like a charm and it was the simplest "manual" way of doing this.
Also if you use React + Redux + Firebase, you can check the library react-redux-firebase that already implements a lot of stuff including the populate that is, similar to the MongoDB populate and the SQL Join:
http://react-redux-firebase.com/docs/populate.html