increment firebase field value in flutter? - firebase

I have a problem with that code below.
I want to create a blog app and I want to let people like posts and when someone clicks the like button it
should increase the field value in firebase and if he clicked again it decrements the value.
My Code : -
bool liked = false;
------------------
onPressed: () async {
await Firestore.instance
.collection('posts')
.document('${widget.uid}')
.updateData(
{
"likes": FieldValue.increment(
(liked ? (-1) : (1)),
),
},
);
setState(() {
liked = !liked;
});
},

Seems like your liked value go back to false even after the setState. Did you check liked before updating data. And could you show us exactly where do you declare your variable.

From your code it just seems like everytime you click the value of 'liked' is false. That makes your code to just increment the value by one. You have to check if the user has liked the post before and then change the state for the 'liked' bool.

Related

Using onWrite Trigger for Realtime database in Firebase function

I designed a flutter application using dart and firebase backend. I want to get triggered when a user creates, delete, or updates anything in the database. I understood onCreate,onRemoved, and onUpdate methods.
I wrote a javascript code in the firebase cloud function. I need to send a notification when a trigger happens. I don't want to use 3 different triggers. I want to use onWrite trigger only.
This is my database.
There are four departments called comp, civil, elect, and mech. I want to get triggered when database changes happen in a single onWrite trigger!
My First question is, I want to differentiate whether it is created or delete or update from onWrite trigger. I know it will trigger for all 3 events. But how can I differentiate it?
This is my code for onCreate...
exports.noticeAddedComp = functions.database.ref('main/notices/comp/{id}').onCreate( async evt => {
var token = ['dxnfr3dq6_Y:APA91bHavtoP62l296qzVoBhzQJbMFA']
const payload = {
notification:{
title : 'Message from Cloud',
body : 'This is your body',
sound : 'default'
},
data:{
message : 'Thi is new Push',
click_action : 'FLUTTER_NOTIFICATION_CLICK',
}
};
await admin.messaging().sendToDevice(token,payload);
});
Above code is working. But it is for onCreate.
My second question is, Do I need to write four onWrite trigger codes for four departments?
You can use the change.before and change.after properties to determine whether the node was created, deleted, or updated in a onWrite handler:
exports.noticeAddedComp = functions.database.ref('main/notices/comp/{id}')
.onWrite( async (change, context) => {
if (!change.before.exists()) console.log("New node: "+change.after.key);
if (!change.after.exists()) console.log("Deleted node: "+change.before.key);
if (change.before.exists() && change.after.exists()) console.log("Updated node: "+change.after.key)
...
});
You can attach a Cloud Function to all departments at once, by including another parameter into its path:
exports.noticeAddedComp = functions.database.ref('main/notices/{dept}/{id}')
.onWrite( async (change, context) => {
console.log("Triggered for department: "+context.params.dept);
...
})
You can check if
evt.after.data().property;
is either null or doesn't exist, meaning it is deleted.
EDIT:
Scenario when you create something (document or field) :
Creation of the field would mean that the field in "before" doesn't exist at all, and in "after" it exists, but can be null.
Scenario when you update something
Field in the "before" is not the same as the one in "after".

Create and update database with input from PageView.builder in flutter

I have a PageView.builder that has a textFormfield and a title. The builder iterates through the elements of the list and once on the last one, there is a submit button that I would like to send the Key : Value pairs to firestore. when I use for each, it only creates the content of the last item of the list multiple times.
here is my create and update function:
Future updateDatabase(String remarkText) async {
return await databaseCollection.document().setData({
questionItems[index].title : questionItems[index].remarkText
});
}
and this is how I call it in my button
onPressed: () async {
questionItems.forEach((question) async {
await updateDatabase(remarkText);
});
},
How can I loop through them to send data for the previous items as well? Please help.
I think it's iterating over all items, but updating always the same item in Firestore. The variable index should be changed in each iteration somehow. Otherwise each iteration will set value on the same questionItems[index].
I hope it will help!

increment a value in firestore with flutter

hi i am trying to increment a value when clicked the button if data is available in firestore this is my code bloc if you have any suggestion lmk please
int q = 0;
final snapShot = await Firestore.instance.collection('cart').document("LIihBLtbfuJ8Dy640DPd").get();
if(snapShot.exists){
q=q+1;
}
Firestore.instance.runTransaction((Transaction transaction) async {
await transaction.update(
Firestore.instance
.collection("cart")
.document("LIihBLtbfuJ8Dy640DPd"),
{
foodItem.name: {
'itemName': foodItem.name,
'imgUrl': foodItem.imageAssetPath,
'itemPrice': foodItem.price,
'quantity': q,
}
});
});
In November 2021, this worked for me.
FirebaseFirestore.instance.collection('users').doc(currentUser?.id).update({
'bronzeBadges': FieldValue.increment(2),
});
var quantityref = db.collection("cart").document("LIihBLtbfuJ8Dy640DPd");
// Increment the quantity field by 1.
quantityref.update({
"quantity" : firebase.firestore.FieldValue.increment(1)});
If your want to change a value based on the previous one, you have basically two approaches:
Make use of transactions. I see you're doing that but incorrectly, because you're fetching the current value outside of it, and it could change by the moment you run the update, causing data inconsistencies. I don't know about Flutter, but as far as I know, a Transaction in Firebase consists in a read operation followed by one or more write operations, and the value returned from the read will be the very last one and won't be changed before you finish the transaction, so you can be sure you're working with the latest one. I suggest you to read the Transactions docs.
increment method (recommended): See this see this answer for incrementing in Flutter
First of all, you need to get the desired document and its elements to update the document of fields. In your example, it is quantity.
First, get the document:
Firestore.instance
.collection('cart')
.document('documentID')
.get()
.then((DocumentSnapshot ds) {
// use ds, parse ds then access the quantity
});
After doing the job, you need to update the field. Thankfully, there is an updateData function in firestore instance.
db.collection('cart')
.document('documentID')
.updateData({'quantity': someQuantity});
Hope it helps.

Flutter Text("${sqlite_tbl[0]['body']") throwing NoSuchMethodError

In this Flutter project, I am displaying information from a local sqlite database onto a page. There are many examples on the internet using the ListView.builder and ListTile to display. However, I am not in this case and I want to be able to access and display a specific column from a table.
First I create an instance of List then make that instance be a rawQuery like so.
List<Map> sqlite_tbl = db.rawQuery('SELECT * FROM sample_table');
Then, in the build method for the page, I place some text in the appBar and in a SingleChildScrollView which is text I retrieve from the database like so..
child: new Text("${sqlite_tbl[0]['title']}",
child: new Text("${sqlite_tbl[0]['body']}",
When I access this page from the previous page, I get the red flash with NoSuchMethodError for a second or two, then the page will display with no errors. In my Run log, it will say The method '[]' was called on null. Receiver: null Tried calling: . So I assume it is the [0] where I retrieve the text, however once I remove that it will say that type argument type 'String' cannot be assigned to parameter type 'int'.
Does anybody know the correct way to retrieve this data or how to fix this issue? Please let me know if you need to see more of my code.
The method db.rawQuery will return the type Future<List<Map>>. You should change your instantiation of the list to be:
List<Map> sqlite_tbl = await db.rawQuery('SELECT * FROM sample_table');
You would then have to call setState.
A better way for you to do this is something like:
List<Map> sqlite_tbl;
bool initialized;
initState() {
super.initState();
initialized = false;
_getData();
}
_getData() {
db.rawQuery('SELECT * FROM sample_table').then((results) {
setState(() {
sqlite_tbl = results;
initialized = true;
});
}).catchError((e) { // do something });
}
And then you would build your UI depending on the value of initialized.

AngularFire - Adding user info to the database after signing in with popup

I was wondering is there any way to store a user info only when he calls $scope.authObj.$signInWithPopup('google'); for the first time ( only once per user ).
Currently every time when "user" clicks on the button to get signed in, his data is stored to the database.
I've tried something like this:
$scope.googleSignIn = function(){
$scope.authObj.$signInWithPopup("google").then(function(data){
$scope.authObj.$onAuthStateChanged(function(user){
for(var prop in firebasedb.users){
if(firebasedb.users[prop].id === data.uid){
console.log('same')
break;
} else {
firebasedb.users.$add({
name: 'Default Name',
id: user.uid
});
}
}
}); // End auth state change
});// End sign in
};// End googleSignIn
This current code prevents adding new user because it is obvious that id's are the same.
I hope I explained it properly.
Thanks in advance

Resources