Как проверить, содержит ли уже поле документа типа array значение с помощью правил Firestore? - PullRequest
0 голосов
/ 13 июля 2020

Учитывая тип документа:

interface Post {
  content: string;
  sharedBy: Array<string>;
}

Ограничение, которое необходимо обеспечить, - позволить пользователям объединять свои uid с массивом sharedBy ровно один раз.

Кроме того, в мои модульные тесты, создается документ, где post.sharedBy изначально []. Следовательно, первое обновление проходит успешно, и значение sharedBy становится ['1'], что подтверждается приведенным ниже запросом ('1' - это тест uid).

После этого выполняется точно такое же обновление, однако вместо сбоя, оно тоже выполняется. * РЕДАКТИРОВАТЬ

Следующее содержимое тестового файла:

import {
  initializeTestApp,
  initializeAdminApp,
  assertSucceeds,
  assertFails,
} from '@firebase/testing';

const projectId = 'projectId';
const myId = '1';
const myAuth = { uid: myId };

const getFirestore = (auth?: typeof myAuth) =>
  initializeTestApp({
    auth,
    projectId,
  }).firestore();

const getAdminFirestore = () =>
  initializeAdminApp({
    projectId,
  }).firestore();

const myPost = {
  content:
    'Lorem ipsum dolor sit amet consectetur, adipisicing elit. Minus, doloribus praesentium nulla pariatur esse laborum a in obcaecati expedita recusandae.',
  sharedBy: [],
};

const getMyPost = () => getAdminFirestore().collection('posts').add(myPost);

describe('App tests', () => {
  test("user can increase any post's share count by 1 only once", async () => {
    const db = getFirestore(myAuth);

    const { id } = await getMyPost();

    console.log((await db.collection('posts').doc(id).get()).data()!.sharedBy); // []

    await assertSucceeds(
      db
        .collection('posts')
        .doc(id)
        .update({ sharedBy: [myId] }),
    );
    console.log((await db.collection('posts').doc(id).get()).data()!.sharedBy); // ['1']
    await assertFails(
      // error
      db
        .collection('posts')
        .doc(id)
        .update({ sharedBy: [myId] }),
    );
  });
});


1 Ответ

1 голос
/ 13 июля 2020

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

Единственный способ обеспечить уникальность в Firestore - это убедиться, что значения являются ключами. Таким образом, вы можете создать sharedBy карту, где ключом является UID пользователя. Таким образом, вы гарантируете, что каждый UID присутствует только один раз, поскольку ключи на карте по определению уникальны.

Другой вариант - сохранить элементы sharedBy в подколлекции, и там тоже использовать UID как идентификатор документа. Таким образом, система уже гарантирует, что идентификаторы уникальны.

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

...