i have this code to get all of documents from firestore:
const getThemesList = async ({ commit }) => {
const snapshot = await firebase
.firestore()
.collection('themes')
.get();
const promiseThemes = snapshot.docs.map(doc => doc.data());
commit(types.GET_THEMES, promiseThemes);
};
by that fuction i can listing, each item have a delete button:
<v-btn text #click="deleteTheme(item)">
Delete
</v-btn>
each item only have these parameters:
{
description: (...)
name: (...)
type: (...)
}
but how can i delete an item, if i dont have their id?
db.collection('themes')
.doc(theme.id)
.delete()
.then(function() {
how can i get the id? theme.id?
Edit 1:
i have this wrong with #DougStevenson's answer
doc is a DocumentSnapshot that has an id property. Just add the document ID into each item object that you generate:
const promiseThemes = snapshot.docs.map(doc => {id: doc.id, ...doc.data());
Now you have an object with an id property that you can use to delete the document.
Related
My problem is that I use wrong query to get the date.
const SaveDateBase = async ( e) => {
e.preventDefault()
await setDoc(doc(db, "Users", "Pompy", "Pompy", user.uid), {
displayName: user.displayName,
uid: user?.uid,
modulyPV}).then(()=>{
console.log("moduly", modulyPV)
})
};
useEffect(() => {
const getUsers = async (users) => {
const URC = query(collection(db, "Users").document("Pompy").collection("Pompy"), where("uid", "==", user?.uid));
const data = await getDocs(URC)
setModulyPV(data.docs.map((doc) => ({...doc.data(), id: doc.id})))
}
getUsers();
},[])
The date are saved in date base, and I can successfully update/delete them, but I do something wrong to fetch (read?) them.
I guess is problem with the code.
You can get the data in diff ways, first "Pompy" seems to be your document where you are storing a nested collection then you document "Pompy" So for retrieve that specific document should be something like:
let snapshot = await db
.collection('Users')
.doc('Pompy')
.collection('Pompy')
.get()
snapshot.forEach(doc =>{
console.log('data:', doc.data())
})
Then to query into the nested collection would be something like querying the nested collections.
https://cloud.google.com/firestore/docs/samples/firestore-data-get-sub-collections?hl=es-419#firestore_data_get_sub_collections-nodejs
You can also use collection groups.
https://firebase.google.com/docs/firestore/query-data/queries#collection-group-query
const pompys = query(collectionGroup(db, 'Pompy'), where("uid", "==", user?.uid));
This question already has an answer here:
How to remove fields from a database?
(1 answer)
Closed 10 months ago.
The application displays news cards on which there is an icon that adds news to Favorites.The added news is added to the Firestore database and displayed on a separate page with a delete icon. I need that when clicking on the icon, the document with this news is deleted from the database. How can I do that?
Icon code with addition:
Widget customListTile(Article article, BuildContext context) {
final _fireStore = FirebaseFirestore.instance;
...
IconButton(onPressed: () async {
newsController.addNews(article);
_fireStore.collection('favoriteItems').add({
'name' : article.source.name,
'title': article.title,
'image': article.urlToImage,
});
},
icon: const Icon(Icons.bookmark_border)),
}
Icon code with removal:
IconButton(onPressed: () {
newsController.removeNews(article);
},
icon: const Icon(Icons.bookmark_remove))
To delete a document, we can use the runTransaction method of the Firestore.instance and use the delete method of the Transaction class.
Flutter - remove a firebase document onTap()
await Firestore.instance.runTransaction((Transaction myTransaction) async {
await myTransaction.delete(snapshot.data.documents[index].reference);
});
First Get your ID
then, run :
IconButton(onPressed: () {
CollectionReference users = FirebaseFirestore.instance.collection('favoriteItems');
Future<void> deleteItems() {
return users
.doc('itemsID')
.delete()
.then((value) => print("Items Deleted"))
.catchError((error) => print("Failed to delete Item: $error"));
}
}, icon: const Icon(Icons.bookmark_remove))
I have create document like this in react native, I am using rnfirebase library
firestore()
.collection('WaterCanData')
.doc(EntryDate)
.collection('Entries')
.doc(values.customerName)
.set({
CustomerName: values.customerName,
CansOut: values.cansOut,
JarsOut: values.jarsOut,
EmptyCansIn: values.emptyCansIn,
JarsIn: values.jarsIn,
Bottles: values.bottles,
Ice: values.ice
})
.then(() => {
console.log('Entry added!!!!!!!!!');
})
When I try to retrieve EntryDate from WaterCanData Coellection I am not able to fetch it(Document name appears in italic font), So how should I retrive this document which contains a subcollection, Below I have attached my ss of data structure
Data structure
Data structuree
The reason your document appears in italics is because it doesn't currently exist. In Cloud Firestore, subcollections can exist without requiring their parent document to also exist.
Non-existant documents will not appear in queries or snapshots in the client SDKs as stated in the Firebase Console.
This document does not exist, it will not appear in queries or snapshots
If you want to be able to get your entry dates, you need to create the document (which can be empty).
firebase.firestore()
.collection('WaterCanData')
.doc(EntryDate)
.set({}); // an empty document
To create the document at the same time as an entry on it's subcollection, you can use a batched write like so:
const db = firebase.firestore();
const batch = db.batch();
// get references to the relevant locations
const entryDateRef = db
.collection('WaterCanData')
.doc(EntryDate);
const customerRef = entryDateRef
.collection('Entries')
.doc(values.customerName);
// queue the data to write
batch.set(entryDateRef, {});
batch.set(customerRef, {
CustomerName: values.customerName,
CansOut: values.cansOut,
JarsOut: values.jarsOut,
EmptyCansIn: values.emptyCansIn,
JarsIn: values.jarsIn,
Bottles: values.bottles,
Ice: values.ice
})
// make changes to database
batch.commit()
.then(() => {
console.log('Entry added!!!!!!!!!');
});
This will then allow you to list all of the entry dates in your database using something like:
firebase.firestore().collection('WaterCanData')
.get()
.then((querySnapshot) => {
querySnapshot.forEach(doc => {
const entryDate = doc.id;
// const customerEntriesRef = doc.ref.collection('Entries');
console.log('Entry date found: ' + entryDate);
}
});
If (as an example) you wanted to also find how many entries were linked to a given date, you would need to also query each subcollection (here the code gets a little more confusing).
firebase.firestore().collection('WaterCanData')
.get()
.then((querySnapshot) => {
const fetchSizePromises = [];
// for each entry date, get the size of it's "Entries" subcollection
querySnapshot.forEach(doc => {
const entryDate = doc.id;
const customerEntriesRef = doc.ref.collection('Entries');
// if this get() fails, just store the error rather than throw it.
const thisEntrySizePromise = customerEntriesRef.get()
.then(
(entriesQuerySnapshot) => {
return { date: entryDate, size: entriesQuerySnapshot.size }
},
(error) => {
return { date: entryDate, size: -1, error }
}
);
// add this promise to the queue
fetchSizePromises.push(thisEntrySizePromise)
}
// wait for all fetch operations and return their results
return Promise.all(fetchSizePromises);
})
.then((entryInfoResults) => {
// for each entry, log the result
entryInfoResults.forEach((entryInfo) => {
if (entryInfo.error) {
// this entry failed
console.log(`${entryInfo.date} has an unknown number of customers in its Entries subcollection due to an error`, entryInfo.error);
} else {
// got size successfully
console.log(`${entryInfo.date} has ${entryInfo.size} customers in its Entries subcollection`);
}
}
});
Using below code you can console every document id inside waterCanData collection. In your database you have only one document, then it will console your document id. (10042021)
firestore()
.collection('WaterCanData')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.id)
});
})
In my cloud function I want to update my document from 'dashboard' collection when a new student added to 'students' collection.
const getActiveStudents = () => {
return db.collection('/students/').where('status', '==', true).get().then(
snapshot => {
let studentsCount = snapshot.docs.length;
db.collection('/dashboard/').where('type', '==', 'students').get().then(
result => {
if (result.docs.length === 0) {
db.collection('dashboard').add({
count: studentsCount,
type: 'students',
label: 'Active students'
});
}else {
result.docs[0].ref.update({
count: studentsCount,
type: 'students',
label: 'Active students'
});
}
return result;
}
).catch(error => {
console.log(error);
});
return snapshot;
}
).catch(error => {
console.log(error);
})
}
exports.onChangesInStudents = functions.firestore.document('/students/{studentId}').onWrite(event => {
getActiveStudents();
return;
});
When I add a new student, instead of updating document it adds a new document to my 'dashboard' collection.
How should I organize my code in order to properly update the quantity of students.
as #Doug mentioned, iterating over the entire collection is too heavy. instead you can stream the query results and iterate over keys, using query.stream().
to access and update a single field in a document, first retrieve the document by its ID with doc(), then use update() while specifying the field.
here's an example of implementation based on your scenario.
package.json
{
"dependencies": {
"firebase-admin": "^6.5.1",
"firebase-functions": "^2.1.0"
}
}
index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const studentsRef = admin.firestore().collection('students');
const dashboardRef = admin.firestore().collection('dashboard');
exports.addStudent = functions.firestore
.document('students/{studentId}')
.onCreate((snap, context) => {
var newStudent = snap.data();
console.log('New student in collection: ', newStudent);
var activeCount = 0;
studentsRef.where('status', '==', true).select().stream()
.on('data', () => {
++activeCount;
}).on('end', () => {
dashboardRef.where('type', '==', 'students').get()
.then(querySnap => {
if (querySnap.docs[0].data().count == activeCount){
console.log('No new active student: ', querySnap.docs[0].data());
} else {
console.log('New active count: ', activeCount);
console.log('Student Dashboard before update: ', querySnap.docs[0].id, '=>', querySnap.docs[0].data());
dashboardRef.doc(querySnap.docs[0].id).update({
count: activeCount
});
console.log('Active student count updated: ', querySnap.docs[0].data().count, '=>', activeCount);
};
});
});
return null
});
gcloud
gcloud functions deploy addStudent \
--runtime nodejs8 \
--trigger-event providers/cloud.firestore/eventTypes/document.create \
--trigger-resource "projects/[PROJECT_ID]/databases/(default)/documents/students/{studentId}"
When a function is triggered, you might want to get data from a document that was updated, or get the data prior to update.
You can get the prior data by using change.before.data(), which contains the document snapshot before the update.
Similarly, change.after.data() contains the document snapshot state after the update.
Node.js
exports.updateUser = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
// Get an object representing the current document
const newValue = change.after.data();
// ...or the previous value before this update
const previousValue = change.before.data();
//...therefore update the document as.
admin.firestore().collection('user').doc(docId).update(snapshot.after.data());
});
Reference:-
https://firebase.google.com/docs/functions/firestore-events
Is there a way to acquire the document id that was generated after adding a document to a collection?
If I add a document to a collection that represents a "post" in a social media app, I want to get that document id and use it as a field in another document in a different collection.
If I can't get the document Id that was generated after adding a document, should I just compute a random string and supply the id when creating the document instead? That way I can use that same string as the field in my other document?
Quick structure example:
POST (collection)
Document Id - randomly generated by firebase or by me
USER (collection)
Document Id - randomly generated by firebase
userPost: String (this will be the document id
in the post collection that I'm trying to get)
Yes it is possible. When you call the .add method on a collection, a DocumentReference object is returned. DocumentReference has the id field, so you can get the id after the document was created.
// Add a new document with a generated id.
db.collection("cities").add({
name: "Tokyo",
country: "Japan"
})
.then(function(docRef) {
console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
console.error("Error adding document: ", error);
});
This example is in JavaScript. Visit the documentation for other languages.
If using promises, I'd recommend using fat arrow function as it opens up the possibility for using this.foo even in the .then function
db.collection("cities").add({
name: "Tokyo",
country: "Japan"
})
.then(docRef => {
console.log("Document written with ID: ", docRef.id);
console.log("You can now also access this. as expected: ", this.foo)
})
.catch(error => console.error("Error adding document: ", error))
Using function(docRef) means you cannot access this.foo, and error will be thrown
.then(function(docRef) {
console.log("Document written with ID: ", docRef.id);
console.log("You can now NOT access this. as expected: ", this.foo)
})
While fat arrow functions will allow you to access this.foo as expected
.then(docRef => {
console.log("Document written with ID: ", docRef.id);
console.log("You can now also access this. as expected: ", this.foo)
})
Edit/addition 2020:
A more popular way these days may be to use async/await instead. Notice that you have to add async in front of the function declaration:
async function addCity(newCity) {
const newCityAdded = await db.collection("cities").add(newCity)
console.log("the new city:", newCityAdded)
console.log("it's id:", newCityAdded.id)
}
And if you only want the id it can be grabbed using descructuring. Destructuring allows you to grab any key/value-pair in the response:
async function addCity(newCity) {
const { id } = await db.collection("cities").add(newCity)
console.log("the new city's id:", id)
}
It's also possible to use destructuring to grab the value and rename to whatever you want:
async function addCity(newCity) {
const { id: newCityId } = await db.collection("cities").add(newCity)
console.log("the new city's id:", newCityId)
}
If you want to use async/await instead of .then(), you can write it like this:
const post = async (doc) => {
const doc_ref = await db.collection(my_collection).add(doc)
return doc_ref.id
}
If you want to catch any errors in this function, include .catch():
const doc_ref = await db.collection(my_collection).add(doc).catch(err => { ... })
or you can have the calling function catch the error.
For Android, Java, you're suppose to get the Document ID before you set() or add() something to Firestore. Like so:
//Fields:
CollectionReference toolsCollectionRef = FirebaseFirestore.getInstance().collection(toolsCollection);
CustomPOJO_Model toolToPost;
//In Methods:
String newDocID= toolsCollectionRef.document().getId(); //Get Doc ID first.
toolToPost.setToolID(newDocID);
//Now use the doc ID:
toolsCollectionRef.document(newDocID).set(toolToPost.getConvertedTool_KeyValuePair ()).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
}
});
//Re-use same ID in another post:
usersCollectionRef.document(mAuth.getUid()).collection(usersToolsCollection).document(toolToPost.getToolID()).set(toolToPost.getConvertedTool_KeyValuePair());
using v9, you can also get the ID even before creating the document
Get a new docRef and read its random id
Use the id as you want
For example, insert the id in the document data
Then create the document
const usersRef = collection(db,'users') // collectionRef
const userRef = doc(usersRef) // docRef
const id = userRef.id // a docRef has an id property
const userData = {id, ...} // insert the id among the data
await setDoc(userRef, userData) // create the document
As others mentioned also, we can get the document reference once it added.
After we get the document reference on the behalf of id, we can update the same
Service.ts file
async funName(data: Data){
let docRef = this.firestore.collection('table-name').add(data);
console.log(docRef)
try {
const docAdded = await docRef;
console.log(docAdded.id);
this.firestore.doc('table-name/' + docAdded.id).update({ id: docAdded.id });
return docRef;
}
catch (err) {
return err;
}
}
component.ts file
async addData(){
try{
let res = await this.dataServ.funName(this.form.value);
this.snackbar.open('success', 'Success');
}catch(ex){
this.disabled = false;
this.snackbar.open('err', 'Error')
console.log(ex, 'exception');
}
}
for FB Firestore version 9 (JS/Web) use the following syntax:
import { addDoc, doc, Timestamp, updateDoc } from "firebase/firestore";
//add document to 'posts' collection with auto id
const newItem = await addDoc(collection(db, 'posts'), {
caption: post.value.caption || "No caption provided",
location: post.value.location || "No location provided",
imageUrl: imageUrl.value,
createdAt: Timestamp.now(),
});
//get new document id an update it to the file as id field.
const fileID = newItem.id
console.log('added file:', fileID);
const updateDocId = doc(db, "posts", fileID) ;
await updateDoc(updateDocId, {
id: fileID
})
I'm not sure why this one was voted out. This is what I needed I was looking for adding the doc().set() instead of doc().add().
I will be using uuid as the document to search for my users inside collection.
firebase.firestore().collection("cities").doc().set({ name: Tokyo,
country: Japan })
According to documentation in firebase v9 i think you'd want to use addDoc() method like so:
import { collection, addDoc } from "firebase/firestore";
// Add a new document with a generated id.
const docRef = await addDoc(collection(db, "cities"), {
name: "Tokyo",
country: "Japan"
});
console.log("Document written with ID: ", docRef.id);
There is also setDoc() method which allows you to set your own id for the document
import { doc, setDoc } from "firebase/firestore";
// Add a new document in collection "cities"
await setDoc(doc(db, "cities", "YOUR_CUSTOM_ID"), {
name: "Los Angeles",
state: "CA",
country: "USA"
});
Here's what I do, as mentioned in your question. Not sure if it is best practice, but it works for easy access.
When creating the document in the first place
firebase.firestore().collection("cities").doc().set({ name: Tokyo,
country: Japan })
you can set the id of the doc and put that exact id in it as a property:
firebase.firestore().collection("cities").doc('id-generated-from-somewhere')
.set({ id: 'id-generated-from-somewhere', name: Tokyo, country: Japan })