Создание документов в разных коллекциях пожарных магазинов с одинаковым ссылочным идентификатором - PullRequest
0 голосов
/ 20 мая 2019

Мой вопрос на самом деле имеет два аспекта, поэтому я не уверен, что мне следует задавать оба вопроса в одном сообщении или создать другое сообщение. Во всяком случае, вот оно:

Я создаю пользователей в базе данных firestore. Я не хочу помещать все детали в один документ, потому что он будет запрашиваться много, и все детали будут извлечены, даже если это не нужно. Поэтому я решил создать коллекцию members_full со всеми сведениями о пользователях, которые мне могут не понадобиться часто, и другую коллекцию под названием members_header, чтобы сохранить несколько самых важных деталей. При создании нового пользователя я хочу, чтобы ссылочный идентификатор в обеих коллекциях был одинаковым для конкретного пользователя.

- members_full -+
                |
                + --- abnGMbre --- +
                                   |
                                   + --- mother : 'His mom'
                                   + --- Father:  'daddy'

- members_header+
                |   
                + ---- abnGMbre -- +
                                   |
                                   + ---- fullname: 'john Doe'
                                   + ---- pictURL: 'path to his profile pic'

Я хочу что-то похожее на вышесказанное. Вот что я сделал в облачной функции:

/** Create / Update a member
 * ------------------------- */
exports.updateMember = functions.https.onCall( (data, context) =>{
  // root member and secretaries are allowed to update members
  const authParams:any = {
    uid:      context.auth.uid,
    email:    context.auth.token.email,
  };
  // Check if user is allowed to perform operation
  return checkPermission(authParams, ['root', 'secretary']).then(res => {
    if(res==false){
      return { // Permission denied
        status: STATUS.permission_denied,
      }
    }
    // set object to add/ update
    const member:any = data;
    // Check if uid of member object is present (true:update, false: create)
    var fullRef : admin.firestore.DocumentReference;
    var headRef : admin.firestore.DocumentReference;
    var countRef: admin.firestore.DocumentReference;
    var createNewMember  = false;
    if(member.uid!==undefined && member.uid!==null){ // update
      fullRef  = fsDB.collection('members_full').doc(member.uid);
      headRef  = fsDB.collection('members_header').doc(member.uid);
    } else {
      fullRef  = fsDB.collection('members_full').doc();
      headRef  = fsDB.collection('members_header').doc(fullRef.id);
      countRef = fsDB.collection('counters').doc('members');
      createNewMember  = true;
    }

    return fsDB.runTransaction(t => {
      return t.get(fullRef).then(doc => {
        // Update full details
        t.set(fullRef, {
          surname     : member.surname     ,
          firstName   : member.firstName   ,
          birthDate   : member.birthDate   ,
          birthPlace  : member.birthPlace  ,
          email       : member.email       ,
          phone       : member.phone       ,
          occupation  : member.occupation  ,
          father      : member.father      ,
          mother      : member.mother      ,
          spouse      : member.spouse      ,
          children    : member.children    ,
          addressHome : member.addressHome ,
          addressLocal: member.addressLocal,
          contactHome : member.contactHome ,
          contactLocal: member.contactLocal,
          comment     : member.comment     ,
          regDate     : member.regDate     ,
        });
        // Update header details
        t.set(headRef, {
          fullName    : member.fullName    ,
          gender      : member.gender      ,
          active      : member.active      ,
          picURL      : member.picURL      ,
        });
        // Increment number of members
        if(createNewMember ){
          t.update(countRef, {count: admin.firestore.FieldValue.increment(1)});
        }

      }).then(() => {
        return { status : STATUS.ok  }
      }).catch(err => {
        return {
          status: STATUS.fail,
          message: err.message,
          error: err
        }
      });
    }).then(() => {
      return { status : STATUS.ok  }
    }).catch(error =>{
      return {
        status: STATUS.fail,
        message: error.message,
        debug:  'run transaction err',
        error: error
      }
    });
  }).catch(err => {
    return {
      status:   STATUS.fail,
      message:  err.message,
      debug:  'check permission err',
      error:    err
    }
  });
});


/** Check if authenticated user's roles are among the ones allowed 
 * --------------------------------------------------------------- */
function checkPermission(authParams:any, allowedRoles:any[]):Promise<boolean>{
  // Check if authenticated user as any of the roles in array 'allowedRoles'
  return new Promise((resolve, reject) => {
    // If one of allowed roles is root, check against global variables
    if(allowedRoles.indexOf('root')>=0 && 
        ( root_auth.email.localeCompare(authParams.email)==0 || 
          root_auth.uid.localeCompare(authParams.uid)==0)){
      resolve(true);
    }
    // Get autID
    const uid = authParams.uid;
    // Get corresponding user in collection roles
    admin.firestore().collection('userRoles').doc(uid).get().then(snap => {
      // Get roles of user and compare against all roles in array 'allowedRoles'
      const memRoles  = snap.data().roles;
      var   found     = false;
      var   zz        = memRoles.length;
      for(let z=0; z<zz; z++){
        if(allowedRoles.indexOf(memRoles[z])){
          found = true;
          break;
        }
      }
      resolve(found);
    }).catch(err => {
      reject(err);
    });
  });
}

Когда я вызываю эту облачную функцию, она записывает только в документ members_full и увеличивает число членов. Это не создает запись в members_header. Мой первый вопрос: где я ошибся? способ получения идентификатора из первого документа для создания второго документа, не так ли?

Второй вопрос, будет ли лучше создавать вложенные коллекции, а не иметь 2 коллекции? если да, как мне сделать это в транзакции?

Помощь очень ценится

1 Ответ

0 голосов
/ 20 мая 2019

Вам необходимо связать вызовы методов в транзакции.Это не очень ясно в документации, но если вы посмотрите на справочный документ для транзакции (https://firebase.google.com/docs/reference/node/firebase.firestore.Transaction), вы увидите, что методы update() и set() возвращают транзакцию, которая является «экземпляром транзакции»).. [and is] используется для цепочки вызовов методов".

Так что вы должны адаптировать свой код следующим образом:

        return fsDB.runTransaction(t => {
            return t.get(fullRef)
            .then(doc => {
                t.set(fullRef, {
                     surname     : member.surname     ,
                     firstName   : member.firstName  
                     //....   
                })
                .set(headRef, {
                     //....
                     gender      : member.gender   
                     //....
                })
                .update(countRef, {count: admin.firestore.FieldValue.increment(1)});
            });
        });

Вам также необходимоправильно соедините все различные обещания следующим образом:

return checkPermission(authParams, ['root', 'secretary'])
.then(res => {
    //...
    return fsDB.runTransaction(t => {
      //.....
    });
.then(t => {
    return { status : STATUS.ok  }
})
.catch(error => {...})

Однако вы можете использовать пакетную запись вместо транзакции, поскольку она появляетсячто вы не используете документ, возвращенный t.get(fullRef) в транзакции.


По второму вопросу, IMHO, нет причин использовать подколлекции вместо двух (корневых) коллекций.

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