Firestore 在更新数组时不会存储两个相同的值

问题描述 投票:0回答:7

使用 flutter,当更新具有 2 个或更多连续相同值的数组时,firestore 只会添加一个。

示例:

void updateValue() {
var now = [new DateTime.now()];
int pain =5;
 Firestore.instance.collection('Patient').document('bC2ML7LaQ1fWGOl37ZUq').collection('Symptom').document('2H6e99Bvrz6h0HBzgnyg')
            .updateData({ 'nauseaLevel' : FieldValue.arrayUnion([pain]), 'nauseaTime':FieldValue.arrayUnion(now)});
          }

当执行该函数2次时,firestore中的数组“nauseaLevel”只会添加一个“pain”值,而忽略第二个。

数组恶心时间按预期工作,因为值不同。

arrays firebase flutter google-cloud-firestore
7个回答
17
投票

根据官方文档关于更新数组中的元素

arrayUnion()
将元素添加到数组中,但仅添加尚未存在的元素。

因此,您无法使用

arrayUnion()
函数在 Cloud Firestore 的数组中添加重复元素。

但是,为了避免误解,您可以在数组中添加重复元素,但前提是您在客户端读取整个数组,进行添加(包含所有重复项),然后将其写回数据库。


2
投票

您不能使用 arrayUnion 来管理必须包含重复项的数组,从 arrayUnion 的定义可以看出。

您可以做的是读取文档,将客户端中的数组修改为您想要的值(包括重复项),然后将数组字段写回 Firestore。您可以通过事务以原子方式完成此操作。


1
投票

我的 Angular 项目也有同样的问题,但是我在应用程序中创建了一个临时数组,我首先将数据推送到该数组中,然后将临时数组添加到 Firestore 中并且它起作用了

tempOrder: order = [];


chosenMeal(meal: string, price: number){
   this.tempOrder.push( {meal, price} );
   this.db.collection('tables').doc(this.table.propertyId).update({order:(this.tempOrder)})
}

正如您从示例中看到的,首先我将所选餐食以及价格作为对象添加到我的临时数组

tempOrder
中,然后在下一行中,我使用来自
 的数据更新 firestore 中的 
order
 数组tempOrder
数组

你可以在firestore中看到想要的结果


0
投票

我写了一篇关于 使用 Flutter 和 Firestore 处理嵌套对象 的文章,其中详细介绍了如何执行此操作。

这是我检索数组、更新数组并将其保存回 Firestore 的示例:

void AddObjectToArray() {
Exercise exercise;
Set newSet;
Firestore.instance
    .collection("exercises")
    .document("docID")
    .get()
    .then((docSnapshot) => {
  newSet = Set(10, 30), 
  exercise = Exercise.fromMap(docSnapshot.data), 
  exercise.sets.add(newSet),
  Firestore.instance.collection("exercises").document("docID").setData(exercise.toMap())
  });
}

还有我的练习和课程:

锻炼

class Exercise {
final String name;
final String muscle;


List<dynamic> sets = [];

  Exercise(this.name, this.muscle);

  Map<String, dynamic> toMap() => {"name": this.name, "muscle": this.muscle, "sets": firestoreSets()};

  List<Map<String,dynamic>> firestoreSets() {
    List<Map<String,dynamic>> convertedSets = [];
    this.sets.forEach((set) {
      Set thisSet = set as Set;
      convertedSets.add(thisSet.toMap());
    });
    return convertedSets;
  }

  Exercise.fromMap(Map<dynamic, dynamic> map)
      : name = map['name'],
        muscle = map['muscle'],
        sets = map['sets'].map((set) {
          return Set.fromMap(set);
        }).toList();
}

设置

class Set {


final int reps;
  final int weight;

  Set(this.reps, this.weight);

  Map<String, dynamic> toMap() => {"reps": this.reps, "weight": this.weight};

  Set.fromMap(Map<dynamic, dynamic> map)
      : reps = map["reps"].toInt(),
        weight = map["weight"].toInt();
}

0
投票
const [myA, setmyA] = useState([])
    const subAnswer = async (ant) => {
    
        if (currentQuestion < 25) {
          myA.push({
          submittedanswer: ant.ant,
          isCorrect: ant.isCorrect,
        },)
        const docRef = doc(db, 'quiz1', `${submittedansid}`)
        await updateDoc(docRef, {
          gevaar: myA })
         }
        }

这适用于我的反应应用程序


0
投票

根据文档“

arrayUnion()
将元素添加到数组中,但仅添加尚未存在的元素。”。有两种方法可以规避它,一种方法是您可以通过读取整个数组客户端在数组中添加重复元素,进行添加(重复),然后将其写回数据库,但这绝对不是最佳的。您可以做的另一个“技巧”是通过使用一些客户端逻辑,您可以检查相同的对象是否已经存在,在这种情况下稍微修改该对象,然后执行
arrayUnion()


0
投票

一种解决方案是将对象推送到数组而不是单一类型。为每个对象创建一个唯一的 IDX。像这样,

另外,看看这段代码,

const docRef = doc(colRef, 'id'); 
// to get unique idx
const auxDoc = doc(workFlowColRef);


await updateDoc(quotaDocRef, {
   last_updated: serverTimestamp(),
   users: arrayUnion({
      uid,
      idx: auxDoc.id
   })
})
© www.soinside.com 2019 - 2024. All rights reserved.