更新Cloud Firestore文件中的个别地图

时间:2019-06-08 13:19:49

标签: javascript firebase google-cloud-firestore

最终更新 我从使用基于以下来自andresmijares的答案的事务更改为使用set()。

这现在允许我将数据写入数据库。

var gradeDocRef = db.collection("students").doc(studentId);
                            console.log(gradeDocRef);

                            var setWithMerge = gradeDocRef.set({
                                "UnitGrades": {
                                            [unitNo]: {
                                                "CG": CG,
                                                "PG": PG, 
                                                "TG": TG
                                                }
                                            }
                                }, { merge: true });

修改 我根据以下andresmijares的评论更改了交易代码。

transaction.set(gradeDocRef, {merge: true}, {

但是却出现此错误?

传递给函数Transaction.set()的未知选项'UnitGrades'。可用选项:merge,mergeFields


我有一个包含集合学生的云Firestore数据库。 每个学生集合都包含一个学生文档,其中包含如下图和子图

UnitGrades: 
    {
     IT1:
       {                                  
        CG: "F"
        PG: "F"                                          
        TG: "F"
        id: "IT1"
        name: "Fundamentals of IT"
        type: "Exam"
    }

地图UnitGrades中有10个单位 每个学生都有相同的单元组合

我想基于Bootstrap中的HTML表单更新地图(该表单可以正常工作,而且很长,因此请不要将其放在此处)

即改变学生成绩

我使用了firestore交易更新文档,并做了一些改动以从HTML表单中获取数据。

let studentId = $(this).attr("data-student-id");
let unitNo = $(this).attr("data-unit");
let CG = $(this).attr("data-CG");
let PG = $(this).attr("data-PG");
let TG = $(this).attr("data-TG");

// Create a reference to the student doc.
var gradeDocRef = db.collection("students").doc(studentId);
console.log(gradeDocRef);
    return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
    return transaction.get(gradeDocRef).then(function(gradeDoc) {

   if (!gradeDoc.exists) {
     throw "Document does not exist!";
}

// update the grades using a transaction

   transaction.update(gradeDocRef, {

// in here is my error, I need to be able to select the map
// for the variable for UnitNo only and not wipe the other maps

    "UnitGrades": {

    [unitNo]: {

    "CG": CG,

    "PG": PG, 

    "TG": TG                                                }
});
});

}).then(function() {

console.log("Transaction successfully committed!");

}).catch(function(error) {

console.log("Transaction failed: ", error);
console.log(studentId);

});

我实现的代码更新了正确的单元图,但随后擦除了其余的UnitGrades。我真正想要的是更新变量

中标识的单元图

UnitNo,然后保持其余单元不变。

例如当前,如果我更新IT1,则可以正确更新地图中的等级,然后从UnitGrades地图中擦除单位IT2,IT3,IT12等。我真的希望IT2,IT3,IT12等保持原样,并使用新值更新IT1。例如,“ F”更改为“ P”

2 个答案:

答案 0 :(得分:1)

更改这些行:

transaction.update(gradeDocRef, {
    "UnitGrades": {
    [unitNo]: {
       "CG": CG,
       "PG": PG, 
       "TG": TG                                                }
});

为此

transaction.set(gradeDocRef, {
    `UnitGrades.${unitNo}`: {
       "CG": CG,
       "PG": PG, 
       "TG": TG 
}, { merge: true });

据我所知,它的工作方式如下:

假设您的文档如下所示:

 {
   "fantasticsFours": {
     "thing": { ... },
     "susan": { ... },
     "mister": { ... }
   }
 }

我们需要添加{"humanTorch" :{...}}

已设置并合并

db.collection('heroes').doc(`xxxXXXxxx`).set({
  "fantasticsFours": {
    "humanTorch":{ ... }
  }
}, {merge:true})

将得到以下数据:

 {
   "fantasticsFours": {
     "thing": { ... },
     "susan": { ... },
     "mister": { ... },
     "humanTorch":{ ... }
   }
 }

使用更新

db.collection('heroes').doc(`xxxXXXxxx`).update({
  "fantasticsFours": {
    "humanTorch":{ ... }
  }
})

将得到以下数据:

 {
   "fantasticsFours": {
     "humanTorch":{ ... }
   }
 }

更多here

答案 1 :(得分:1)

以下应该可以解决问题:

  //....
  return db.runTransaction(function(transaction) {
    // This code may get re-run multiple times if there are conflicts.
    return transaction
      .get(gradeDocRef)
      .then(function(gradeDoc) {
        if (!gradeDoc.exists) {
          throw 'Document does not exist!';
        }

        // update the grades using a transaction


        transaction.update(
          gradeDocRef,
          'UnitGrades.' + unitNo,
          {
            CG: CG,

            PG: PG,

            TG: TG
          }
          // in here is my error, I need to be able to select the map
          // for the variable for UnitNo only and not wipe the other maps
        );
      })
      .then(function() {
        console.log('Transaction successfully committed!');
      })
      .catch(function(error) {
        console.log('Transaction failed: ', error);
        console.log(studentId);
      });

这样做

transaction.update(gradeDocRef, {
    "UnitGrades": { ... }
});

您要用新地图替换整个 UnitGrades字段,因此,您将删除现有地图和子地图的值。

您需要做的是仅替换特定的“子图”。为此,您需要使用dot notation,如documentation中的update()方法所述:“字段可以包含点,以引用文档中的嵌套字段。”

请注意,有两种方法可以调用update()方法:

update(documentRef: DocumentReference, data: UpdateData): Transaction

update(documentRef: DocumentReference, field: string | FieldPath, value: any, ...moreFieldsAndValues: any[]): Transaction

在这种情况下,我们使用第二种方法,并使用'UnitGrades.' + unitNo(点表示法)定义嵌套“子图”的路径。


HTML测试器页面

如果要测试建议的解决方案,只需将以下代码本地保存为HTML文件,并在a /调整了Firebase配置并b /创建了ID为{{1}的Firestore文档后,在浏览器中将其打开。 } 1集合下。然后更改students的值,在浏览器中刷新页面,您将在数据库中看到更新。

unitNo