Перенос вложенных данных из базы данных в реальном времени в Firestore - PullRequest
0 голосов
/ 23 февраля 2019

Я перемещаю базу данных Firebase Realtime в Firestore и у меня есть вложенные данные

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

Пример:

"data" : {
  "-LYBzlXPoN0137KRLovk" : {
    "-LYC-HHqDFgL9PovJiBr" : {
      "age" : 35,
      "country" : "Country",
      "date" : "2019-02-08T13:07:10+01:00",
      "gender" : "male",
      "id" : 1549627467620,
    },
    "age" : 35,
    "country" : "Country",
    "date" : "2019-02-08T13:04:27+01:00",
    "gender" : "male",
    "id" : 1549627467620,

Я хочу создать вложенную коллекцию из вложенного массива в Firestore.Поэтому я попробовал следующее (облачная функция):

exports.migrateVisits = functions.database.ref('/data/{key}/{nestedKey}')
    .onWrite((change:any, context:any) => {
        // Get a reference to the Firestore document of the changed user
        let userDoc = admin.firestore()
            .collection(`data/{key}/nestedKeys`)
            .doc(context.params.nestedKey);
        // If this user has been deleted, delete in Firestore also
        if (!change.after.exists()) {
            return userDoc.delete();
        }
        // Get the user object with the new changes,
        // as opposed to its value before the edit
        let userData = change.after.val();
        // Now update Firestore with that change

        return userDoc.set(userData);
    });

Но я получаю сообщение об ошибке: Error: Argument "data" is not a valid Document. Input is not a plain JavaScript object.

Есть ли у вас какие-либо идеи по переносу вложенных вложенных данных наилучшим образом?

Обновление для Renaud

exports.migrateVisits = functions.database.ref('/data/users/{userId}/visits/{visit}')
    .onWrite((change:any, context:any) => {
        let userData = change.after.val();
        const mainDocObj:any = {};

        let batch = admin.firestore().batch();

        Object.keys(userData).forEach(e => {
            console.log(e);
            if (
                e == 'age' ||
                e == 'country' ||
                e == 'date' ||
                e == 'gender' ||
                e == 'id' ||
                e == 'lastVisit' ||
                e == 'magazineRoute' ||
                e == 'magazineRouteDone' ||
                e == 'magazineRouteLastDate' ||
                e == 'name' ||
                e == 'notice' ||
                e == 'onNextVisit' ||
                e == 'pause' ||
                e == 'placements' ||
                e == 'plz' ||
                e == 'street' ||
                e == 'tag' ||
                e == 'type'
            ) {  //here, add the other main keys, e.g. with ['gender', 'age', 'country', ....].includes(e)
                mainDocObj[e] = userData[e];
            } else {
                //it needs to be added as a doc in the sub-collection
                const subDocRef = admin
                    .firestore()
                    .collection(`users/${context.params.userId}/vi/${context.params.visit}/rv`)
                    .doc(e);
                batch.set(subDocRef, userData[e]);
            }
        });

        //We first write the mainDoc
        console.log(mainDocObj);
        return admin
            .firestore()
            .collection(`users/${context.params.userId}/vi`)
            .doc(context.params.visit)
            .set(mainDocObj)
            .then(() => {
                //We then write the children in one batch
                return batch.commit();
            });
    });

1 Ответ

0 голосов
/ 23 февраля 2019

Следующие действия должны помочь:

exports.migrateVisits = functions.database.ref('/data/{key}/{nestedKey}')
    .onWrite((change:any, context:any) => {
        // Get a reference to the Firestore document of the changed user

        const key = context.params.key;

        const userDoc = admin
          .firestore()
          .collection('data/' + key + '/nestedKeys')              
          .doc(context.params.nestedKey);

        // If this user has been deleted, delete in Firestore also
        if (!change.after.exists()) {
            return userDoc.delete();
        }
        // Get the user object with the new changes,
        // as opposed to its value before the edit
        let userData = change.after.val();
        // Now update Firestore with that change

        return userDoc.set(userData);
    });

Вы должны использовать context.params, чтобы получить значения path.


ОБНОВЛЕНИЕ следуя нашим комментариям.

Главное, на что нужно обратить внимание, так это то, что теперь мы слушаем на уровне /data/{key}, вы должны отличать данные, принадлежащие основному документу, от данных, принадлежащих дочерним элементам.,В приведенном ниже коде я предлагаю сделать это на основе имени данных (пол, дата, возраст, идентификатор ...).Если во время цикла вы встретите элемент данных с другим именем (например, с идентификатором, например -LYC-HHqDFgL9PovJiBr), это означает, что это дочерний документ.

Еще один момент, на который следует обратить внимание, - это использование пакетной записи, см. https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes

Кроме того, я позволю вам взять на себя проверку, если документ удален на нет.Другим аспектом, который вам, возможно, придется адаптировать, является управление уже существующими детьми, в случае, если вы изменяете возраст, например, под узлом -LYC-HHqDFgL9PovJiBr, потому что в этом случае триггер все равно произойдет на уровне /data/{key}.

exports.migrateVisits = functions.database
  .ref('/data/{key}')
  .onWrite((change:any, context:any) => {
    const key = context.params.key;
    let userData = change.after.val();
    const mainDocObj = {};

    let batch = admin.firestore().batch();

    Object.keys(userData).forEach(e => {
      if (e === 'gender') {  //here, add the other main keys, e.g. with ['gender', 'age', 'country', ....].includes(e)
        mainDocObj[e] = userData[e];
      } else {
        //it needs to be added as a doc in the sub-collection
        const subDocRef = admin
          .firestore()
          .collection('data/' + key + '/nestedKeys')
          .doc(e);
        batch.set(subDocRef, userData[e]);
      }
    });

    //We first write the mainDoc
    return admin
      .firestore()
      .collection('data')
      .doc(key)
      .set(mainDocObj)
      .then(() => {
        //We then write the children in one batch
        return batch.commit();
      });
  });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...