【问题标题】:Cloud Function that moves documents between collection在集合之间移动文档的云功能
【发布时间】:2019-07-06 15:28:20
【问题描述】:

我有三个集合:“过去”、“今天”和“未来”。

“today”集合应该只有一个文档。

在午夜,我需要在我的“未来”集合中找到一个具有“下一个”字段的文档,或者,如果没有这样的文档,找到一个在“数字”字段中的值比在“我的“今天”集合中文档的编号”字段。然后我需要将“今天”的文档移动到“过去”集合中,并将找到的文档从“未来”集合移动到“今天”集合。

据我所知,没有“移动”方法,所以我必须使用删除和创建的组合,这需要在一个事务中完成。

我想出了如何执行“调度程序”部分,但不知道如何编写其余部分(文档的实际移动)。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const firestore = admin.firestore();    

exports.scheduledFunction = functions.pubsub.schedule('0 0 * * *')
.onRun((context) => {

  //I need to move my documents... 
});

你能帮我写代码吗?

【问题讨论】:

  • 您似乎在要求 Stack Overflow 为您编写解决方案。这不是它真正的工作方式。我建议尝试解决方案,然后在此处发回有关未按您期望的方式工作的详细信息。
  • 我只是找不到一个好的文档来编写代码,即使是“一个无法按我期望的方式工作的解决方案”。有一点关于这个(例如,事务如何工作),一点关于那个(如何写入集合等),但我不能将它们组合成一个“解决方案”。

标签: google-cloud-firestore google-cloud-functions


【解决方案1】:

您可能在错误的地方寻找文档。它不在具有云功能的 Firestore/Extend 中。它在 Firestore 基本文档中,但您必须将代码类型切换为 node-js。 https://firebase.google.com/docs/firestore/query-data/order-limit-data

您必须通过两个查询来收集数据:在今天和未来的集合中。 通过这些查询,您可以获得文档及其数据。 比你只需要在过去制作一个文档,今天删除并制作一个新的文档(或重写现有的文档),并在将来删除。

我将如何在一个简单的可调用函数中做到这一点:

exports.scheduledFunction = functions.pubsub.schedule('0 0 * * *')
.onRun(async (context) => {
    try {
        let queryToday = admin.firestore().collection('today'); //you can add .limit(1)
        const todaySnapshot = await queryToday.get();
        const todayDoc = todaySnapshot.docs[0];
        const todayData = todayDoc.data();
        const todayToPastRef = admin.firestore().doc(`past/${todayData.documentUid}`);
        /* or how the id is stored? you can just call 
        const todayToPastRef = admin.firestore().collection('past').doc()
        and it will be generated automatically
        */
        const promises = [];
        promises.push(todayToPastRef.set(todayData));
        let queryFuture = admin.firestore().collection('future').orderBy('date').limit(1);
        /*
        or how is the date stored? Idk if firebase allows to query by Timestamp
        you just want to fetch the closest date after today so the order is ascending
        */
        const futureSnapshot = await queryFuture.get();
        const futureDoc = futureSnapshot.docs[0];
        const futureData = futureDoc.data();
        const futureToTodayRef = admin.firestore().doc(`today/${futureData.documentUid}`);
        promises.push(futureToTodayRef.set(todayData));
        promises.push(futureDoc.ref.delete());
        
        promises.push(todayDoc.ref.delete());
        /*
        or you can try to change today's doc data, but the id will remain the same
        promises.push(todayDoc.ref.update(futureData))
        */
        return Promise.all(promises); // function will be executed after all the promises are fullfilled or rejected
    } catch (err) {
        return Promise.reject(err);
    }
});

请注意,我使用 async/await 而不是 .then() 和 .catch()。

使用 console.log() 进行调试,并尝试使用 VSCode,这样您就可以检查对象的方法和属性,这很有帮助

更新: 是的,你可以用一批来做。还有一个例子:

exports.scheduledFunction = functions.pubsub.schedule('0 0 * * *').onRun((context) => {
    const db = admin.firestore();
    let queryToday = db.collection('today');    
    let queryFuture = db.collection('future').orderBy('date').limit(1);
    const batch = db.batch();
    return queryToday
        .get()
        .then(todaySnapshot => {
            const todayDoc = todaySnapshot.docs[0];
            const todayData = todayDoc.data();
            const todayToPastRef = db.doc(`past/${todayData.docUid}`);
            batch.set(todayToPastRef, todayData);
            batch.delete(todayDoc.ref);
            return queryFuture.get();
        })
        .then(futureSnapshot => {
            const futureDoc = futureSnapshot.docs[0];
            const futureData = futureDoc.data();
            const futureToTodayRef = db.doc(`today/${futureData.docUid}`);
            batch.set(futureToTodayRef, futureData);
            batch.delete(futureDoc.ref);
            // now two operations are completed, you just can commit the batch
            return batch.commit();
        })
        .catch(err => {
            // if todaySnapshot or futureSnapshot were not fetched, batch wont be commited
            // or, for example, if snapshots were empty
            return Promise.reject(err)
        });
});

您还可以使用 .getAll() 或类似的方法并行获取文档。你应该测试和实验

【讨论】:

  • 这说明了很多;该链接也有帮助。我对 Promise 和 async/await 构造还不是很熟悉,所以你能告诉我这段代码是否保证这个操作链不会仅部分完成吗?就像何时从“今天”中删除文档,但由于某种原因,在“未来”中找不到新文档并移至“今天”等。我的意思是,我需要这些操作(从“今天”中删除,在“过去”中创建,从“未来”中“删除”,在“今天”中创建)执行全部或不执行。我虽然那是我需要交易或类似的东西的地方。
猜你喜欢
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
  • 2022-01-17
  • 2018-08-01
  • 2021-05-02
  • 2020-10-19
  • 2021-06-17
  • 2022-01-01
相关资源
最近更新 更多