I'm a novice when it comes to coding (started teaching myself ~year ago), any help will be much appreciated, thank you in advance.
I saw that there is 3-4 other post on stack overflow on how to access Firestore's sub-collections.
I tried them all and had no luck, hence why I'm posting this as a new question.
right now I have my data set is up as: collection/document.array. And that was fine till now because I just needed to read that data from the array to draw it out in my little React project with .reduce and .map and push new data to that array on input.
this is the code I have right now for getting data from Firestore:
--- in firebase.js ----------------------------------------------------------------------
export const fire = firebase.initializeApp(config);
export const db = fire.firestore()
_________________________________________________________________________________________
--- in events-context.js ----------------------------------------------------------------
const fetchEvents = async () => {
try {
const data = await db.collection('events').get();
setEvents(data.docs.map(doc => ({ ...doc.data(), id: doc.id })));
} catch ({ message }) {
alert(`Error # fetchEvents, Error:${message}`);
}
};
But now I want to add edit and a remove feature, but in order to do that, I need to carry out my array of data into a sub-collection so each individual element from that array had its own id so that I could later target it. so it needs to be set up something like this: collection/document/sub-collection
To access a document inside a collection, you must know the document ID from another source. This can be done by managing the names inside an array of strings or maps that you can then process within your app per your design.
For example: once created, you will have a snapshot of the reference of which you can store the document id inside the parent document:
db.collection("events").doc(id).update({
payers: firebase.firestore.FieldValue.arrayUnion(paySnapshot.ref.id)
})`
Once you have this information, you can append it to the relevant document path using one of the following techniques.
db.collection("events").doc(id).collection("payers").doc(pay_id).get()
db.doc(\events/${id}/payers/${pay_id}`).get()`
I strongly advise against using .get() on a collection without limit() and where() conditions to reduce the reads that can occur.
Try this, it works for me :)
Insert data >>>
const q = query(collection(this.fire, "events"));
const querySnapshot = await getDocs(q);
const queryData = querySnapshot.docs.map((details) => ({
...details.data(),
id: details.id,
}));
console.log(queryData);
queryData.map(async (v, id) => {
await setDoc(doc(this.fire, `events/${auth}/more`, events.title), {
'title': events.title,
'uid': auth,
//your data here
})
})
Read Data >>>
const querySnapshot = await getDocs(collection(this.fire,
`/events/${auth}/more/`)); querySnapshot.forEach((doc) => { //
doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data()); });
return querySnapshot;
Related
I am very new to firebase and I am unable to fetch the blog port with the help of Slug key value. I tried out few things but all were unsuccessful.
Can anyone help me out in fetching the data please?
I want to fetch my blog post data with the help of Sulg URL, not behalf of key.
See the image below
I have this key value quickly-extract-email-address-from-text
with the help of ID i am getting this blog post data.
const [article, setArticle] = useState([]);
useEffect(() => {
const docRef = doc(db, "BlogArticles", id);
onSnapshot(docRef, (snapshot) => {
setArticle({ ...snapshot.data(), id: snapshot.id });
});
}, []);
but i want the same data with the help of this key value quickly-extract-email-address-from-text
It sounds like you're asking how to execute a query against Firestore. Based on that, you'll want something like this for the query:
const articlesRef = collection(db, "BlogArticles");
const q = query(citiesRef, where("slug", "==", "quickly-extract-email-addresses-from-text"));
onSnapshot(q, (snapshot) => {
snapshot.forEach((doc) => {
setArticle({ ...doc.data(), id: doc.id });
})
});
Keep in mind that if your database would ever contains multiple documents matching the query, this would only end up showing the last of those matches.
I have a screen on my app where a user inputs a number {x} and from this number I would like to create a collection in the programs doc and then add {x} documents to the collection.
Only one document gets added to the collection.
const handleContinue = async () => {
const batch = writeBatch(db);
const blockArray = [...Array(blockCount).keys()];
// use the program name as the ID.
const docRef = doc(db, `Users/${userStore.uid}/programs/${programName}`);
const payload = {
title: programName,
units: programUnits,
system: programSystem,
status: programStatus,
days: dayCount,
blocks: blockCount,
};
await setDoc(docRef, payload, { merge: true });
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const dRef = doc(db, `Users/${userStore.uid}/programs/${programName}`);
const cRef = collection(dRef, "blocks");
blockArray.forEach((index) => {
const insert = doc(cRef, `block_${index}`);
batch.set(insert, { name: `Block ${index}` });
});
await batch.commit();
}
};
Structure I'm expecting starting from programs doc
-programs (doc)
-- programs fields
-- blocks (collection) <-- known collection name
--- block_1 (doc)
--- block_2 (doc)
--- block_3 (doc)
...etc
block_1, block_2 etc would be the document ID.
As far as I can see in the code you're writing multiple documents, but all to the same collection: Users/${userStore.uid}/programs/${programName}/blocks.
If you want to create multiple collections, you'll need to vary one of the odd-indexed parameters in this path, like blocks_1, blocks_2, etc. Note though that this is not recommended in most scenarios, as the client-side SDKs have no way to request a list of the collections under a specific path, so it's typically best to use hard-coded collection names - or collection names that are implicitly known in some other way.
So I found that my array I was looping over wasn't what I expected, nothing to do with Firebase. Fixed it further upstream and now I get the results I was after.
Above is my Js code
I have a database that has information regarding the location of an apartment, I am trying to search for a specific property to see if it exists in the database. The user will be able to key into the search box to perform the search.
"propertiesRef" is used to store the user input.
I tried storing the data into "q" that I received from querying the database. But I have no idea how to read the result.
This is the console log for "q", but I don't quite understand the information that is shown, I want to know which output in the console should I be looking at and how do I access them?
The query() function just creates an instance Query. You need to use getDocs() function to actually fetch data from Firestore.
const search = (property) => {
const propertiesRef = collection(db, "flats-table");
const q = query(propertiesRef, where("name", "==", property))
return getDocs(q).then((qSnap) => {
const data = qSnap.docs.map(d => ({ id: d.id, ...d.data() }))
console.log(data);
return data;
})
// or use async-await
// const qSnap = await getDocs(q);
}
Checkout the documentation for more examples.
I'm learning firebase cloud functions with JavaScript,
I get a QuerySnapshot back of a collection of documents each document holds an ID field and a message field.
Where I'm stuck now is that every time I loop through the collection I want to be able to just take the ID field out from each object and save it.
I've tried all the ways that I can think of that come up on Google and stack overflow none are working for me, I'm obviously doing something wrong.
I'm totally new to JavaScript so this may be an easy fix if anyone has any information
This is my code in visual studio that I'm using, which is working fine from where I can see to get to the collection that I need to
// onDelete is my trigger which would then go and fetch the collection that I want
exports.onDelet = functions.firestore.document('recentMsg/currentuid/touid/{documentId}').onDelete(async(snap, context) => {
const data = snap.data();
const contex = context.params;
// once I get the information from onDelete the following code starts
await admin.firestore().collection(`messages/currentuid/${contex.documentId}`)
.get()
.then((snapshot) => {
//this array will hold all documents from the collection
const results = []
const data = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
results.push(data)
console.log(results)
//This is one of the ways I've tried
//results.forEach((doc) => {
//console.log(doc.id)
//this is a print out in the terminal
// > undefined
// } );
});
Below is a print out that I get in terminal which is all the information that it holds which is great,
But really all I want is to have an array that holds every id
if there was just one value in the array I know this would not be a problem but because there is an object with multiple values that's the issue.
i functions: Beginning execution of "onDelet"
> [
> [
> { id: '28ZyROMQkzEBBDwTm6yV', msg: 'sam 2' },
> { id: 'ixqgYqmwlZJfb5D9h8WV', msg: 'sam 3' },
> { id: 'lLyNDLLIHKc8hCnV0Cgc', msg: 'sam 1' }
> ]
> ]
i functions: Finished "onDelet" in ~1s
once again apologies if this is a dumb question I'm a newbie.
With await admin.firestore().collection(messages/currentuid/${contex.documentId}) .get() you get a QuerySnapshot that supports forEach and not map. Just write your code like this:
// onDelete is my trigger which would then go and fetch the collection that I want
exports.onDelet = functions.firestore.document('recentMsg/currentuid/touid/{documentId}').onDelete(async(snap, context) => {
const data = snap.data();
const contex = context.params;
// once I get the information from onDelete the following code starts
await admin.firestore().collection(`messages/currentuid/${contex.documentId}`)
.get()
.then((snapshot) => {
//this array will hold all documents from the collection
const results = []
snapshot.forEach((doc) =>{
results.push({id:doc.id,...doc.data()})
});
console.log(results)
//This is one of the ways I've tried
//results.forEach((doc) => {
//console.log(doc.id)
//this is a print out in the terminal
// > undefined
// } );
});
I assume that messages/currentuid/${contex.documentId} is a collecion and not a single document.
You can read more baout it here.
I am trying to fetch all fieldnames inside of payload > (random doc id) objects.
Currently I am fetching other collections with:
async fetchPage() {
const query = firebase
.firestore()
.collection('PAGES')
.where('type', '==', 'page')
try {
const { docs } = await query.get()
this.pageIndex = docs.map((doc) => {
if (doc && doc.exists) {
this.items = doc.data()
}
let { id } = doc
const data = doc.data()
return { id, ...data }
})
console.log('Loaded items', this.items)
} catch (error) {
throw new Error('Something gone wrong!')
}
},
The first question is: What is the best practice to query objects? I read this in firebase docs but didn't lead me to any results trying it out that way.
Second question, since the child object of payload is the actual id of its document, what method must I use to declare that I'm looking for e.g payload > doc id > content: "This is some content"?.
Here are some information that are helpful about how Firestore operates and they may prove helpful to you on how to improve queries in your database.
Here is the Firebase documentation about queries and the Query Client Library.
This is an article that refers to the causes of slow queries.
Regarding your second question you can get a snapshot of the whole document and then you have to iterate through the data.
Let me know if this is helpful to you.