Firestore云功能以递归方式更新子集合/集合组

时间:2020-04-27 08:02:30

标签: javascript firebase recursion google-cloud-firestore google-cloud-functions

我具有此云功能:

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 个答案:

答案 0 :(得分:1)

我提出了一个解决方案,虽然没有遵循问题的上下文,但是可以轻松地将其组合在一起。希望它可以帮助其他人。

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;
};

相关问题