Обновление индивидуальной карты в облачном документе пожарного депо - PullRequest
3 голосов
/ 08 июня 2019

Окончательное обновление Я перешел от использования транзакции, основанной на ответе ниже от 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}, {

но тогда получите эту ошибку?

Неизвестная опция 'UnitGrades' передана в функцию Transaction.set (). Доступные опции: объединить, объединить поля


У меня есть база данных облачного пожарного магазина, которая содержит коллекцию студентов. Каждая коллекция учеников содержит студенческий документ с картой и подкартой, как показано ниже

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

У меня есть 10 юнитов на карте. Каждый студент имеет одинаковую комбинацию единиц

Я хочу обновить карту на основе 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, это корректно обновляет оценки в карте, но затем стирает единицы IT2, IT3, IT12 и т. Д. С карты UnitGrades. Я действительно хочу, чтобы IT2, IT3, IT12 и т. Д. Оставались неизменными, а IT1 обновлялся новыми значениями. например, «F» меняется на «P»

Ответы [ 2 ]

1 голос
/ 08 июня 2019

Следующее должно сделать трюк:

  //....
  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 поле новой картой, поэтому вы стираете существующую карту и значения вложенных карт.

Что вам нужно сделать, это заменить только определенную «подкарту». Для этого вам необходимо использовать точечную нотацию , как описано в документации для метода update(): «Поля могут содержать точки для ссылки на вложенные поля в документе».

Обратите внимание, что есть два разных способа вызова метода update():

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

или

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

В этом случае мы используем второй способ и определяем путь вложенной «подкарты» с помощью 'UnitGrades.' + unitNo (точечная запись).


Страница HTML-тестера

Если вы хотите протестировать предлагаемое решение, просто сохраните локально следующий код в виде файла HTML и откройте его в браузере после того, как вы / Адаптировали конфигурацию Firebase и b / создали документ Firestore с идентификатором 1 в коллекция students. Затем измените значение unitNo, обновите страницу в браузере, и вы увидите обновления в БД.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>

    <script src="https://www.gstatic.com/firebasejs/6.1.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/6.1.1/firebase-firestore.js"></script>
  </head>

  <body>
    <script>
      // Initialize Firebase
      var config = {
        apiKey: 'xxxxxx',
        authDomain: 'xxxxxx',
        databaseURL: 'xxxxxx',
        projectId: 'xxxxxx',
        appId: 'xxxxxx'
      };

      firebase.initializeApp(config);

      var db = firebase.firestore();

      let studentId = '1';
      let unitNo = 'IT1';
      let CG = 'F';
      let PG = 'F';
      let TG = 'F';

      // Create a reference to the student doc.
      var gradeDocRef = db.collection('students').doc(studentId);
      console.log(gradeDocRef);
      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!';
            }

            transaction.update(
              gradeDocRef,
              '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);
          });
      });
    </script>
  </body>
</html>
1 голос
/ 08 июня 2019

изменить эти строки:

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":{ ... }
   }
 }

Подробнее здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...