gpt4 book ai didi

javascript - 嵌套的 Javascript promise - 从 Firestore 获取数据

转载 作者:行者123 更新时间:2023-12-04 08:35:56 25 4
gpt4 key购买 nike

在过去的 3 天里,我一直被这个错误所困扰,我几乎尝试了一切,尝试以 1000 种方式构建 promise ,但似乎没有任何效果。也许我正在失去“大局”,所以希望新的眼睛会有所帮助。谢谢阅读:
我有一个在 Firebase Cloud Functions 中运行的预定函数。代码试图完成的是

  • 检查文档是否过期并将其更改为“非事件”>> 这部分有效
  • 如果文档设置为非事件状态,我想查看 Firestore 数据库中是否还有其他相同“类型”的文档。如果没有其他相同类型的文档,那么我想从我的文档“类型”中删除该类型。

  • 在我最近的尝试中(复制如下),我检查快照中是否有文档(这意味着存在另一个相同类型的文档,因此不必删除该文档)。然后如果 res!== true,我会删除该文件。
    问题是,出于某种原因, res 永远不会为真......也许“res” promise 在“快照” promise 之前解决?
    const functions = require('firebase-functions');
    const admin = require('firebase-admin');
    admin.initializeApp();

    exports.scheduledFunction = functions.pubsub
    .schedule('0 23 * * *').timeZone('Europe/Madrid')
    .onRun( async (context) => {

    const expiredDocs = await admin.firestore().collection('PROMOTIONS_INFO')
    .where('active','==',true)
    .where('expiration', '<=', new Date())
    .get()
    .then(async (snapshot) => {
    await Promise.all(snapshot.docs.map( async (doc) => {
    doc.ref.update({active: false})
    const type = doc.data().business.type
    const id = doc.data().id

    const exists = await admin.firestore().collection('PROMOTIONS_INFO')
    .where('active','==',true)
    .where('business.type','==', type)
    .where('id', '!=', id)
    .limit(1)
    .get()
    .then((snapshot) => {
    snapshot.docs.map((doc)=>{return true})
    }).then(async (res) => {
    res===true ? null :
    (await admin.firestore().collection('PROMOTIONS_INFO').doc('types')
    .update('types', admin.firestore.FieldValue.arrayRemove(type)))
    })
    }))
    });
    });

    最佳答案

    为了达到您想要的结果,您可能需要考虑使用 Batched Writes并将您的代码拆分为不同的步骤。
    一组可能的步骤是:

  • 获取所有仍处于事件状态的过期文档
  • 没有过期文件?记录结果和结束函数。
  • 对于每个过期的文件:
  • 将其更新为非事件状态
  • 存储类型以备后用

  • 对于要检查的每种类型,检查是否存在具有该类型的事件文档,如果不存在,则存储该类型以供稍后删除。
  • 没有要删除的类型?记录结果和结束函数。
  • 删除所有需要删除的类型。
  • 记录结果和结束函数。

  • 上述步骤中,步骤3可以利用 Batched Writes步骤 6 可以使用 arrayRemove() field transform可以删除 multiple elements at once以减轻数据库的负担。

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

    exports.scheduledFunction = functions.pubsub
    .schedule('0 23 * * *').timeZone('Europe/Madrid')
    .onRun( async (context) => {
    // get instance of Firestore to use below
    const db = admin.firestore();

    // this is reused often, so initialize it once.
    const promotionsInfoColRef = db.collection('PROMOTIONS_INFO');

    // find all documents that are active and have expired.
    const expiredDocsQuerySnapshot = await promotionsInfoColRef
    .where('active','==',true)
    .where('expiration', '<=', new Date())
    .get();

    if (expiredDocsQuerySnapshot.empty) {
    // no expired documents, log the result
    console.log(`No documents have expired recently.`);
    return; // done
    }

    // initialize an object to store all the types to be checked
    // this helps ensure each type is checked only once
    const typesToCheckObj = {};

    // initialize a batched write to make changes all at once, rather than call out to Firestore multiple times
    // note: batches are limited to 500 read/write operations in a single batch
    const makeDocsInactiveBatch = db.batch();

    // for each snapshot, add their type to typesToCheckObj and update them to inactive
    expiredDocsQuerySnapshot.forEach(doc => {
    const type = doc.get("business.type"); // rather than use data(), parse only the property you need.
    typesToCheckObj[type] = true; // add this type to the ones to check
    makeDocsInactiveBatch.update(doc.ref, { active: false }); // add the "update to inactive" operation to the batch
    });

    // update database for all the now inactive documents all at once.
    // we update these documents first, so that the type check are done against actual "active" documents.
    await makeDocsInactiveBatch.commit();

    // this is a unique array of the types encountered above
    // this can now be used to check each type ONCE, instead of multiple times
    const typesToCheckArray = Object.keys(typesToCheckObj);

    // check each type and return types that have no active promotions
    const typesToRemoveArray = (await Promise.all(
    typesToCheckArray.map((type) => {
    return promotionsInfoColRef
    .where('active','==',true)
    .where('business.type','==', type)
    .limit(1)
    .get()
    .then((querySnapshot) => querySnapshot.empty ? type : null) // if empty, include the type for removal
    })
    ))
    .filter((type) => type !== null); // filter out the null values that represent types that don't need removal

    // typesToRemoveArray is now a unique list of strings, containing each type that needs to be removed

    if (typesToRemoveArray.length == 0) {
    // no types need removing, log the result
    console.log(`Updated ${expiredDocsQuerySnapshot.size} expired documents to "inactive" and none of the ${typesToCheckArray.length} unique types encountered needed to be removed.`);
    return; // done
    }

    // get the types document reference
    const typesDocRef = promotionsInfoColRef.doc('types');

    // use the arrayRemove field transform to remove all the given types at once
    await typesDocRef.update({types: admin.firestore.FieldValue.arrayRemove(...typesToRemoveArray) });

    // log the result
    console.log(`Updated ${expiredDocsQuerySnapshot.size} expired documents to "inactive" and ${typesToRemoveArray.length}/${typesToCheckArray.length} unique types encountered needed to be removed.\n\nThe types removed: ${typesToRemoveArray.sort().join(", ")}`);
    注:错误检查被省略,应该被实现。
    批次限制
    如果您希望达到每批次 500 次操作的限制,您可以在批次周围添加一个包装器,以便它们根据需要自动拆分。此处包含一种可能的包装器:
    class MultiBatch {
    constructor(dbRef) {
    this.dbRef = dbRef;
    this.batchOperations = [];
    this.batches = [this.dbRef.batch()];
    this.currentBatch = this.batches[0];
    this.currentBatchOpCount = 0;
    this.committed = false;
    }

    /** Used when for basic update operations */
    update(ref, changesObj) {
    if (this.committed) throw new Error('MultiBatch already committed.');
    if (this.currentBatchOpCount + 1 > 500) {
    // operation limit exceeded, start a new batch
    this.currentBatch = this.dbRef.batch();
    this.currentBatchOpCount = 0;
    this.batches.push(this.currentBatch);
    }
    this.currentBatch.update(ref, changesObj);
    this.currentBatchOpCount++;
    }

    /** Used when an update contains serverTimestamp, arrayUnion, arrayRemove, increment or decrement (which all need to be counted as 2 operations) */
    transformUpdate(ref, changesObj) {
    if (this.committed) throw new Error('MultiBatch already committed.');
    if (this.currentBatchOpCount + 2 > 500) {
    // operation limit exceeded, start a new batch
    this.currentBatch = this.dbRef.batch();
    this.currentBatchOpCount = 0;
    this.batches.push(this.currentBatch);
    }
    this.currentBatch.update(ref, changesObj);
    this.currentBatchOpCount += 2;
    }

    commit() {
    this.committed = true;
    return Promise.all(this.batches.map(batch => batch.commit()));
    }
    }
    要使用它,请换出 db.batch()new MultiBatch(db) 的原始代码中.如果批处理中的更新(例如 someBatch.update(ref, { ... }) )包含字段转换(例如 FieldValue.arrayRemove() ),请确保使用 someMultiBatch.transformUpdate(ref, { ... })而是将单个更新正确计为 2 个操作(读取和写入)。

    关于javascript - 嵌套的 Javascript promise - 从 Firestore 获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64796463/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com