Flutter中如何更新Firestore文档数组内指定map元素的字段值
Firestore数组内嵌套Map字段更新问题解决方案
问题根源
FieldValue.arrayUnion的判断逻辑为仅当插入元素与数组内现有元素完全相等时才会去重,修改answer字段后的对象与原有对象属性不一致,会被判定为新元素插入数组,因此出现重复数据。
方案1:保留现有数据结构的实现方式
如果不调整现有数据模型,可先读取完整的questions数组,本地修改对应下标元素的answer字段后,直接覆盖更新整个questions字段:
void _onPressed(AsyncSnapshot snapshot, int index, String answer) async { var firebaseUser = FirebaseAuth.instance.currentUser; // 拷贝当前完整的questions数组避免直接修改快照数据 List<dynamic> currentQuestions = List.from(snapshot.data!["questions"]); // 更新对应下标元素的answer字段 currentQuestions[index]["answer"] = answer; // 覆盖写入整个数组 await firestoreInstance .collection("test") .doc(firebaseUser.uid) .collection("content") .doc("document") .update({"questions": currentQuestions}); }
注意:如果存在多用户并发修改同一份文档的场景,需要搭配Firestore事务使用避免覆盖冲突,单用户操作自有数据时无需额外处理
方案2:更合理的数据结构优化
数组下标不具备稳定性,后续调整问题顺序后会出现更新错位的问题,建议将questions调整为键值对结构,用问题唯一ID作为key:
// 优化后的数据结构 "content" -> document -> "questions": { "q_001": { "q" : "Are you good?", "info" : "Just say yes or no", "answer" : "yes" }, "q_002": { "q" : "are you playing ball", "info" : "football, soccer, basketball..", "answer" : "no" } }
优化后可直接原子更新指定问题的answer字段,无需读取全量数组,性能和稳定性更高:
void _onPressed(String questionId, String answer) async { var firebaseUser = FirebaseAuth.instance.currentUser; await firestoreInstance .collection("test") .doc(firebaseUser.uid) .collection("content") .doc("document") .update({"questions.$questionId.answer": answer}); }
内容的提问来源于stack exchange,提问作者can-I-do
相关产品推荐
相关产品推荐

