Обновление поля карты во всех документах в Firestore - PullRequest
0 голосов
/ 21 февраля 2019

Я делаю веб-приложение на Angular 6 и библиотеку angularfire2 .У меня есть две коллекции, teams и users.Если имя команды изменяется, имя команды также должно быть изменено внутри документа пользователя.

export interface User {
  firstName: string;
  emailAddress: string;
  team: TeamId;
}

export interface UserId extends User {
  id: string;
}

export interface Team {
  name: string;
  abbreviation?: string;
}

export interface TeamId extends Team {
  id: string;
}

Класс:

const team: Team = {
  name: 'Yankees',
  abbreviation: 'YKS'
};

this.teamService.updateTeam('kbdf673bksbdj', team)
  .then(async res => {
    // The name has changed
    if ('Yankees' !== team.name) {
      await this.teamService.updateTeamNameInOthers('kbdf673bksbdj', team.name);
    }
  }, err => {
  });

Из службы:

private teamsCollection: AngularFirestoreCollection<Team>;
teams: Observable<TeamId[]>;

constructor(
  private afs: AngularFirestore) {
  this.teamsCollection = afs.collection<Team>('teams');

  this.teams = this.teamsCollection.snapshotChanges().pipe(
    map(actions => actions.map(a => {
      const data = a.payload.doc.data() as Team;
      const id = a.payload.doc.id;
      return {id, ...data};
    }))
  );
}

updateTeamNameInOthers(id: string, newName: string) {
  this.userService.getUsers().subscribe(users => {
    users.forEach(user => {
      if (user.team.id === id) {
        this.afs.collection('users').doc(user.id)
          .set({team: {name: newName}}, {merge: true});

        // I have tried
        // .update({team: {name: newName}});
      }
    });
  });
}

Я пытался (транзакция):

updateTeamNameInOthers(id: string, newName: string) {
    this.userService.getUsers().subscribe(users => {
      users.forEach(user => {
        if (user.team.id === id) {
          const userRef = this.afs.collection(config.collection_users).doc(user.id).ref;

          this.afs.firestore.runTransaction(transaction => {
            transaction.get(userRef).then(userDoc => {
              transaction.update(userRef, {team: {name: newname}}, {merge: true});
            });
          });
        }
      });
    });
  }

Вы можете обновить любое свойство Team прямо сейчас, но, если вы хотите изменить все свойства команды одновременно, документ пользователя будетне обновляется.Я не уверен, что это лучший способ сделать это в любом случае.

Моя цель - если имя команды изменилось, измените имя команды во всем документе пользователя, который принадлежит этой команде.

1 Ответ

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

Есть много способов сделать это.Я не рекомендую вносить эти изменения из внешнего интерфейса.

Если ваша структура базы данных:

teams/team

users/user {
  team: { (not as a subcollection)
    id: string;
  }
}

Тогда вам придется опрашивать всех пользователей, таких как вы.Разница в том, что вы захотите использовать транзакцию для выполнения всех операций вместе или вообще не выполнять их при возникновении ошибки.Затем вы будете использовать транзакцию для выполнения операций с БД, как показано в связанном ответе db.firestore.runTransaction(transaction => и transaction.X, где X - ваш метод БД.

В качестве альтернативы , я рекомендую сделатьэтот вид функциональности с облачными функциями .Благодаря этому вы можете прослушивать изменения в записи, не полагаясь на клиентскую сторону для внесения изменений.Если пользователь вносит корректное изменение, облачные функции могут выполнять транзакционные изменения вместо ненадежного выполнения изменений на стороне клиента.

После редактирования 1 Вы должны переместить строку this.afs.firestore.runTransaction(transaction => {выше users.forEach(user => {, поэтому все операции могут использовать одну и ту же транзакцию.Таким образом, если с одним из обновлений произошла ошибка, ни одно из них не будет обновлено.

После чата Окончательное решение состояло в том, чтобы использовать async / await с firestore.runTransaction, вернуть обещаниеобновите записи с помощьюaction.update, разрешив обещание после.Вторая часть решения заключалась в том, чтобы гарантировать, что вы не подписаны на коллекцию, которую вы обновляете в рамках обновления!

// service method
getData(value: string): Promise<FancyType[]> {
  return this.afs.collection<FancyType>(
    'collection',
    ref => ref.where('value', '==', value)
  ).snapshotChanges()
  .pipe(
    take(1),
  ).toPromise();
}

// update method 1 transaction
const data: FancyType[] = await this.service.getData();

if (data) {
  await this.afs.firestore.runTransaction(t => {
    return new Promise((res, rej) => {
      data.forEach(d => {
        const dataRef = this.afs.collection('collection').doc(d.id).ref;
        transaction.update(dataRef, {...d, hello: 'World'});
      });
      res();
    });
  });
}

// alternate update method 2 batch
const data: FancyType[] = await this.service.getData();
const batch = this.afs.firestore.batch();

if (data) {
  data.forEach(d => {
    const dataRef = this.afs.collection('collection').doc(d.id).ref;
    batch.update(dataRef, {...d, hello: 'World'});
  });

  batch.commit()
    .then(res => {
      //on success
    }).catch(err => {
      //on error
    });
}

Вот справочник для транзакций и пакетов.

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