firebase - 在 Firestore 中使用 runTransaction 方法的同时写入操作不起作用
问题描述
我正在开发一个可以获取反馈的颤振应用程序。所以,我需要一次处理多个表单提交。我正在使用 firestore 中提供的 runTransaction 方法来处理它。但是,当我尝试从两台设备同时提交反馈表时,只会记录来自一台设备的响应。
文档中提到,如果任何客户端修改文档,runTransaction 方法会重试事务。但是,在我的情况下并没有发生这种情况。我该如何解决这个问题?
这是我编写的代码。
uploadFeedback(context) {
ProgressDialog pr = new ProgressDialog(context);
pr.style(message: 'Submitting response');
pr.show();
var ref = Firestore.instance.collection('/feedbacks').document(widget.data);
Firestore.instance.runTransaction((transaction) async {
// Read operation
var doc = await ref.get();
var prev = doc['scores'];
attended = doc['attended'];
attended.add(email);
for (int i = 0; i < questionObjectList.length; i++) {
int response = questionObjectList[i].response;
prev[i.toString()][response - 1] += 1;
}
updated = prev;
// Update operation
return transaction.update(ref, {
'scores': updated,
'attended': attended
});
}).then((val) {
pr.hide();
Fluttertoast.showToast(msg: 'Feedback submitted successfully');
}).catchError((e) {
pr.hide();
Fluttertoast.showToast(msg: 'Some error occured');
throw Error();
});
}
还附上整个文件的代码
import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:feedback_system/public/Metrics/effort_rating.dart';
import 'package:feedback_system/public/Metrics/goalcompletionrate_meter.dart';
import 'package:feedback_system/public/Metrics/questionandresponse.dart';
import 'package:feedback_system/public/Metrics/satisfaction_rating.dart';
import 'package:feedback_system/public/Metrics/smiley_rating.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:progress_dialog/progress_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Answer extends StatefulWidget {
final String data;
Answer({this.data});
@override
_AnswerState createState() => _AnswerState();
}
class _AnswerState extends State<Answer> {
var data;
double avg = 0;
var attended;
bool perform = false;
String email;
var updated;
var _doc;
List<QuestionAndResponse> questionObjectList =
new List<QuestionAndResponse>();
instantiate() async {
await Firestore.instance
.collection('/feedbacks')
.document(widget.data)
.get()
.then((_data) {
if (!_data.exists) {
setState(() {
data = 'Error';
});
} else {
setState(() {
data = _data;
});
}
});
}
getSharedPreferences() async {
await SharedPreferences.getInstance().then((val) {
setState(() {
email = val.getString("email");
});
});
}
@override
void initState() {
super.initState();
getSharedPreferences();
instantiate();
}
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
if (data == null)
return SpinKitThreeBounce(color: Colors.blue);
else if (data == 'Error')
return stopUser('Feedback no longer exists');
else if (data['attended'].contains(email))
return stopUser('Can\'t give feedback more than once');
else
return fetchDocument(width);
}
stopUser(data) {
return Scaffold(
body: Center(
child: Text(data),
));
}
fetchDocument(double width) {
return Scaffold(
appBar: AppBar(
title: Text(data['name']),
),
body: ListView.separated(
separatorBuilder: (context, index) =>
Divider(height: 1.0, color: Colors.grey),
itemBuilder: (context, index) {
if (index == data['questions'].length) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: RaisedButton(
color: Color(0xff23272B),
child: Text(
'Submit',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
uploadFeedback(context);
},
),
);
}
return Padding(
padding: EdgeInsets.fromLTRB(5, 2, 5, 2),
child: Column(
children: <Widget>[
ListTile(
leading: Text(
(index + 1).toString() + ")",
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
title: Text(
data['questions'][index],
style: TextStyle(fontSize: 15),
),
),
SizedBox(
height: 5,
),
metric(index)
],
),
);
},
itemCount: data['questions'].length + 1,
),
);
}
metric(int index) {
switch (data['metrics'][index]) {
case 'Satisfaction':
return slider(index);
case 'SmileyRating':
return smiley(index);
case 'EffortScore':
return effortScore(index);
case 'GoalCompletionRate':
return goalCompletionRate(index);
default:
return Text('Unexpected error');
}
}
goalCompletionRate(int index) {
QuestionAndResponse temp =
QuestionAndResponse(data['questions'][index], "GoalCompletionRate");
questionObjectList.add(temp);
return GoalCompletionRateMeter(temp);
}
effortScore(int index) {
QuestionAndResponse temp =
QuestionAndResponse(data['questions'][index], "EffortScore");
questionObjectList.add(temp);
return EffortRatingMeter(temp);
}
smiley(int index) {
QuestionAndResponse temp =
QuestionAndResponse(data['questions'][index], "SmileyRating");
questionObjectList.add(temp);
return SmileyRatingMeter(temp);
}
slider(int index) {
QuestionAndResponse temp =
QuestionAndResponse(data['questions'][index], "Satisfaction");
questionObjectList.add(temp);
return SatisafactionRatingMeter(temp);
}
uploadFeedback(context) {
ProgressDialog pr = new ProgressDialog(context);
pr.style(message: 'Submitting response');
pr.show();
var ref = Firestore.instance.collection('/feedbacks').document(widget.data);
Firestore.instance.runTransaction((transaction) async {
var doc = await ref.get();
var prev = doc['scores'];
attended = doc['attended'];
attended.add(email);
print(attended);
for (int i = 0; i < questionObjectList.length; i++) {
int response = questionObjectList[i].response;
prev[i.toString()][response - 1] += 1;
}
updated = prev;
return transaction.update(ref, {
'scores': updated,
'attended': attended
});
}).then((val) {
pr.hide();
Fluttertoast.showToast(msg: 'Feedback submitted successfully');
}).catchError((e) {
pr.hide();
Fluttertoast.showToast(msg: 'Some error occured');
throw Error();
});
}
}
我不知道我是否以正确的方式使用 runTransaction 方法。因为在 Flutter 中使用 Firestore 没有合适的文档。
提前致谢!
解决方案
推荐阅读
- firebase - 包含数组的 Firestore 复合索引的 JSON 格式是什么?
- python - 当使用 Apache/uWSGI 或 Werkzeug 时,flask json 输出看起来会有所不同
- string - 无法使用 if 表达式而不是 if 语句追加到字符串
- c++ - MySQL 连接器/C++ 与 g++8.1.0 和 C++17 崩溃
- json - jq - 替换数组中的一些变量
- python - 使用 LSTM 生成音乐 - 损失停止减少
- c++ - Thrift 并发:未解决的外部问题
- amazon-web-services - 适用于 B2B 场景的 AWS Cognito 用户池
- ruby-on-rails - 日期格式问题的Rails
- c++ - 使用 [] 运算符时的“类型的绑定引用丢弃限定符”