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))
Related
I'm building an app that contains pet adoption offers. Each pet document has an ID that's generated by DateTime.now() + the user ID to make it unique, anyway, I'm trying to write a deleting method within the Slidable widget to delete the adoption offer.
The problem is that I'm unable to reach the document ID to delete it.
Is there a way to delete a document without getting the ID?
This is the Firebase database
Here is my current code
Future getOffersList() async {
List<PetTile> tiles = [];
List<Slidable> slidables = [];
var data = await FirebaseFirestore.instance
.collection('pets')
.where('owner',
isEqualTo: FirebaseAuth.instance.currentUser!.uid.toString())
.get();
_petsList = List.from(data.docs.map((doc) => Pet.fromSnapshot(doc)));
for (var pet in _petsList) {
tiles.add(PetTile(pet: pet));
}
for (var tile in tiles) {
slidables.add(
Slidable(
child: tile,
endActionPane: ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (value) async {
var ref = FirebaseFirestore.instance
.collection('pets')
.where('id', isEqualTo: tile.pet.id)
.get();
// Deleting...
},
backgroundColor: Color(0xFFFE4A49),
foregroundColor: Colors.white,
icon: Icons.delete,
label: 'Delete',
),
],
),
),
);
}
}
You can get the id of the document by doing the following steps:
Add await infront when you're accessing the conditioned data from firebase collection.. in your case in front of FirebaseFirestore.instance
*This will return a QuerySnapshot rather than a Future instance of the same.
You need to get the doc and the id of that doc.. write:
final id= ref.docs[0].id
*Using first index(0) because i am assuming that only one pet id matches with other pet id.
since you have the id now.. you can perform the delete function
I'm having trouble validating a text form field before data is uploaded to the Firestore database. There aren't any issues with Firestore, only with the way I have written my code.
The validation is to check that the text field is not null or empty, the same as the Flutter codelab. If the text field is empty an error message should appear and the user should remain on the same page until the text field has data. Once the text field is valid the data should be saved to Firestore, a snackbar confirmation should appear on the page and the user should be navigated to a different page.
With the code I have written the user navigates to the new page and the snackbar message appears even if all of the text form fields are empty (invalid). I tried to remove extra code to make it easier to view the code. In my form I have three text fields with identical validation rules. Any help would be greatly appreciated. Thanks.
My Text Form Field:
TextFormField(
labelText: 'Trivia Game Url',
onChanged: (val) {
triviaGameImageURL = val as String;
},
controller: _triviaGameImageURLController,
validator: _triviaGameImageURLValidator,
),
Validation method:
String? _triviaGameImageURLValidator(value) {
if (value == null || value.isEmpty) {
return 'Image Url is required';
}
return null;
}
Method to update Firestore when user taps button:
Future<void> createFirestoreTriviaGame() async {
final form = _formKey.currentState;
if (form!.validate()) {
setState(() {
_isLoading = true;
});
String triviaGameID = const Uuid().v4();
Map<String, dynamic> triviaGameMap = {
FirebaseString.triviaGameID: triviaGameID,
FirebaseString.triviaGameImageURL: triviaGameImageURL,
};
await firestoreMethods
.addTriviaGameData(
triviaGameData: triviaGameMap,
triviaGameID: triviaGameID,
)
.then((value) {
setState(() {
_isLoading = false;
});
});
}
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(SnackBarString.triviaGameCreated),
),
);
Timer(const Duration(seconds: 2), () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const AddTriviaGamePage(),
),
);
});
}
In your code the snackbar and navigation is outside the if (form!.validate()) block. Simply extend this block to include everything that you want to execute only on a valid form, and display a message if validation fails.
The snackbar and navigation should happen on successful save only, after Firestore async call completes. I recommend not to mix async/await with .then, these are the same. So simple await Firestore method, put this in a try/catch block and execute snackbar and navigation on success.
You need to wrap the textfield in a form widget and assign a form key to the form widget
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
Form(
key: formKey,
child: Column(
children: [
... your text fields
// validate
if (formKey.currentState!.validate()) {
I have a Firebase document "coupon" that has 2 fields inside: an array of strings and an integer as seen below
Currently if a user clicks on a button to get a coupon, it will remove the 0 index at Firebase and show that removed array as coupon code in a Text widget, but if two or more users click on the button at the same time they all get the same string from the array.
This is my button on click code currently:
try {
await FirebaseFirestore.instance
.runTransaction((transaction) async {
DocumentReference
couponCollectionReference =
FirebaseFirestore.instance
.collection('coupons')
.doc(widget.couponNumber);
DocumentReference userCollectionReference =
FirebaseFirestore.instance
.collection('users')
.doc(getUserID());
setState(() {
couponTitle = couponCode[0];
couponBlur = 0.0;
isButtonWorking = false;
});
transaction
.update(couponCollectionReference, {
'coupon_code': FieldValue.arrayRemove(
[couponCode[0]]),
});
transaction
.update(couponCollectionReference, {
'coupons_available':
FieldValue.increment(-1),
});
transaction
.update(userCollectionReference, {
'current_points':
FieldValue.increment(-100),
});
await screenshotController
.capture(
pixelRatio: 2,
delay: Duration(milliseconds: 20))
.then((capturedImage) async {
ShowCapturedWidget(
context, capturedImage!);
}).catchError((onError) {
print(onError);
});
});
} catch (e)
Are transactions the way to go and I'm just not implementing them right or am I using a totally wrong approach ?
In order for the coupon document to be considered part of the transaction, you have to read it from the database through the transaction object (and use the value of coupons from there).
In your code that'd be something like this:
await FirebaseFirestore.instance
.runTransaction((transaction) async {
DocumentReference
couponCollectionReference =
FirebaseFirestore.instance
.collection('coupons')
.doc(widget.couponNumber);
DocumentSnapshot couponDoc = await transaction.get(couponCollectionReference); // 👈
couponCode = (couponDoc.data() as Map<String, dynamic>)['coupons'];
...
Im trying to implement code in Firestore which will get the values of a specific object inside a doc in firestore, unfortunently i couldnt find the way to do it.
This is my query code:
useEffect(() => {
firebase
.firestore()
.collection("users")
.doc(uid)
.collection("confirmed-appointments")
.get()
.then((snapshot) => {
let service = [];
snapshot.forEach((doc) => {
service.push(doc.data());
});
console.log("Services: ", service[0].servicesSelected); //Checking if i can get the serviceSelected Obj
});
}, []);
This is a image of the firestore:
What i want is to get the data of the Red circle object, move it to a local object in the code and then present its data inside the app.
any suggestions?
As far as I can tell from the above images, document 10 contains an array, which means that you will need to index into that array in order to get its elements. You can leverage the following code to fetch the servicesSelected object fields:
import firestore from '#react-native-firebase/firestore';
firestore()
.collection('users')
.doc(uid)
.collection("confirmed-appointments")
.get()
.then(querySnapshot => {
//let service = [];
console.log('Total confirmed appointments: ', querySnapshot.size);
querySnapshot.forEach(documentSnapshot => {
console.log("Services Selected: ", documentSnapshot.data().YOUR_ARRAY[1].servicesSelected);
//service.push(documentSnapshot.data());
//console.log('Appointment ID: ', documentSnapshot.id, documentSnapshot.data());
});
});
Note that I assume that servicesSelected lives at index 1 of YOUR_ARRAY (replace YOUR_ARRAY with its actual name).
You can refer to the officially recommended documentation for more details about React Native for Firebase.
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.