我们正在尝试通过事务更新 Firebase 中的数组字段,尽管每次执行时都表明文档已更新,但 iOS 应用程序意外崩溃,并且在检查 Firebase 控制台时文档根本没有被修改
static void createQuestionThread({
required BuildContext context,
required String questionId,
required String ownerId,
required Task task,
required String body,
}) async {
if (body.isNotEmpty) {
var questionRef =
tasksRef.doc(task.id).collection('questions').doc(questionId);
try {
await FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot questionSnapshot =
await transaction.get(questionRef);
if (questionSnapshot.exists) {
List<dynamic> threads =
List.from(questionSnapshot.get('threads') ?? []);
threads.add({
'body': body,
'createdAt': FieldValue.serverTimestamp(),
'ownerId': ownerId,
});
transaction.update(questionRef, {'threads': threads});
print('Document updated successfully');
// Show success SnackBar
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(
const SnackBar(
content: Text('Your question has been posted'),
),
);
} else {
print('Question document does not exist');
// Show error SnackBar
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(
const SnackBar(
content: Text('Failed to post question. Please try again.'),
),
);
}
});
} on FirebaseException catch (e) {
print('Firestore error: ${e.message}');
print('Error code: ${e.code}');
print('Error details: ${e.stackTrace}');
// Show error SnackBar
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(
const SnackBar(
content: Text('An error occurred while posting the question.'),
),
);
} catch (e) {
print('Error updating document: $e');
// Show error SnackBar
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(
const SnackBar(
content: Text('An error occurred while posting the question.'),
),
);
}
} else {
// Show error SnackBar for empty body
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(
const SnackBar(
content: Text('Please enter a question before posting.'),
),
);
}
}
Firebase 规则
// Questions
match /questions/{questionId} {
allow read: if isLoggedIn();
allow create: if request.resource.data.body is string &&
request.resource.data.body != null &&
request.resource.data.body.trim() != "" &&
request.resource.data.ownerId is string &&
request.resource.data.createdAt is timestamp;
allow update: if isLoggedIn() &&
// Check if only the threads field is being updated
request.resource.data.diff(resource.data).affectedKeys().hasOnly(['threads']) &&
// Check if the threads field is an array
request.resource.data.threads is list &&
// Check if each thread in the array is a map with the required fields
request.resource.data.threads.hasAll(['body', 'createdAt', 'ownerId'])
}
使用现场线程修改文档,将一组新的映射添加到现有数组
您的代码似乎将一个项目添加到名为
threads
的(大概)数组字段中,但您的安全规则似乎假设这些项目的所有子字段都存在于文档本身中。
我认为没有办法以这种方式强制执行数组字段中项目的类型,因此请考虑将
threads
设为问题文档的子集合,以便您可以在那里强制执行这些规则。