Облачная функция Firestore для рекурсивного обновления subcollection / collectionGroup - PullRequest
3 голосов
/ 27 апреля 2020

У меня есть эта облачная функция:

import pLimit from "p-limit";


const syncNotificationsAvatar = async (
  userId: string,
  change: Change<DocumentSnapshot>
) => {
  if (!change.before.get("published") || !change.after.exists) {
    return;
  }

  const before: Profile = change.before.data() as any;
  const after: Profile = change.after.data() as any;
  const keysToCompare: (keyof Profile)[] = ["avatar"];
  if (
    arraysEqual(
      keysToCompare.map((k) => before[k]),
      keysToCompare.map((k) => after[k])
    )
  ) {
    return;
  }

  const limit = pLimit(1000);

  const input = [
    limit(async () => {
      const notifications = await admin
        .firestore()
        .collectionGroup("notifications")
        .where("userId", "==", userId)
        .limit(1000)
        .get()

      await Promise.all(
        chunk(notifications.docs, 500).map(
          async (docs: admin.firestore.QueryDocumentSnapshot[]) => {
            const batch = admin.firestore().batch();
            for (const doc of docs) {
              batch.update(doc.ref, {
                avatar: after.avatar
              });
            }
            await batch.commit();
          }
        )
      );
    })
  ];

  return await Promise.all(input);
};


Как я могу рекурсивно обновить коллекцию notifications, но сначала ограничить запрос до 1.000 документов (пока не будет больше документов), а затем batch.update их? Я боюсь, что этот запрос истечет время ожидания, так как коллекция может расти со временем.

1 Ответ

1 голос
/ 06 мая 2020

Публикация решения, которое я разработал, не следуя контексту вопроса, но его можно легко объединить. Надеюсь, это поможет кому-то еще.

import * as admin from "firebase-admin";

const onResults = async (
  query: admin.firestore.Query,
  action: (batch: number, docs: admin.firestore.QueryDocumentSnapshot[]) => Promise<void>
) => {
  let batch = 0;
  const recursion = async (start?: admin.firestore.DocumentSnapshot) => {
    const { docs, empty } = await (start == null
      ? query.get()
      : query.startAfter(start).get());
    if (empty) {
      return;
    }
    batch++;
    await action(
      batch,
      docs.filter((d) => d.exists)
    ).catch((e) => console.error(e));
    await recursion(docs[docs.length - 1]);
  };
  await recursion();
};

const getMessages = async () => {
  const query = admin
    .firestore()
    .collection("messages")
    .where("createdAt", ">", new Date("2020-05-04T00:00:00Z"))
    .limit(200);

  const messages: FirebaseFirestore.DocumentData[] = [];

  await onResults(query, async (batch, docs) => {
    console.log(`Getting Message: ${batch * 200}`);
    docs.forEach((doc) => {
       messages.push(doc.data());
    });
  });
  return messages;
};

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