简体   繁体   English

Firebase 函数在同一个 onCall 中读取和添加数据 function

[英]Firebase Functions read and add data in same onCall function

I have a function that is triggered when I click a button.我有一个 function 当我点击一个按钮时触发。 Based on the docId I can retrieve the right download URL in Firestore.根据 docId,我可以在 Firestore 中检索正确的下载 URL。 But I also want to update a specific field (availableDownloads) in my "customers" collection.但我也想更新我的“客户”集合中的特定字段(availableDownloads)。 I can't get it to work.我无法让它工作。

This code works fine.此代码工作正常。 It returns the download url.它返回下载 url。

exports.getDownloadUrl = functions.https.onCall(async(data, context) => {
    var docRef= await db.collection('projects').doc(data.docId);
    return docRef.get().then(function(doc){
        const downloadURL = doc.data().downloadURL;
        return downloadURL;
    }).catch(function(error) {
        // Handle error
    });
});

However this doesn't.然而事实并非如此。 It returns null它返回 null

exports.getDownloadUrl = functions.https.onCall(async(data, context) => {
    var docRef= await db.collection('projects').doc(data.docId);
    return docRef.get()
    .then(async function(doc){
        const downloadURL = doc.data().downloadURL;
        const userRef = await db.collection('customers').doc(context.auth.uid);
        return userRef.update({
            availableDownloads: admin.firestore.FieldValue.increment(-1)
        }).then(()=> {
            return downloadURL;
        }).catch((error)=> {
            
        })
        
    }).catch(function(error) {
        // Handle error
    });
});

The first thing that jumps out at me is that .update() is an asynchronous function so you need an await in front of userRef.update(...) .跳出来的第一件事是.update()是一个异步 function所以你需要在userRef.update(...)前面await

You should also consider sticking to either arrow functions ( () => {} ) or anonymous functions ( function () {} ), but that's just a stylistic note.您还应该考虑坚持使用箭头函数 ( () => {} ) 或匿名函数 ( function () {} ),但这只是一种风格说明。 :) :)

ETA: as Frank van Puffelen pointed out, you don't need await s for simply declaring a DocumentReference since those are not async functions. ETA:正如 Frank van Puffelen 指出的那样,您不需要await来简单地声明 DocumentReference ,因为它们不是异步函数。 (looking at the line var docRef= await db.collection('projects').doc(data.docId); ). (查看var docRef= await db.collection('projects').doc(data.docId); )。

In addition to the potential problems due to the mix of async/await with then/catch , your main problem is due to variable scoping .除了由于async/awaitthen/catch的混合而导致的潜在问题之外,您的主要问题是由于变量作用域 The downloadURL variable is a local variable declared inside the first then() block and is therefore not accessible in the second then() block. downloadURL变量是在第一个then()块中声明的局部变量,因此在第二个then()块中不可访问。

You can easily see the problem with the following code:您可以使用以下代码轻松查看问题:

  function later(delay, value) {
    return new Promise((resolve) => setTimeout(resolve, delay, value));
  }

  later(500, 'value1')
    .then((value) => {
      console.log('First then block: ' + value);
      const downloadURL = value;
      return later(1000, 'value2');
    })
    .then((value) => {
      console.log('Second then block: ' + value);
      console.log('Second then block: ' + downloadURL); // Here it is going to throw an error
    })
    .catch((error) => {
      console.log(error);
    });

You need to declare the downloadURL variable in the scope of the Cloud Function, as follows:需要在云Function的scope中声明downloadURL变量,如下:

exports.getDownloadUrl = functions.https.onCall((data, context) => {
    let downloadURL;
    const docRef = db.collection('projects').doc(data.docId);
    return docRef.get()
        .then((doc) => {
            downloadURL = doc.data().downloadURL;
            const userRef = db.collection('customers').doc(context.auth.uid);
            return userRef.update({
                availableDownloads: admin.firestore.FieldValue.increment(-1)
            });
        })
        .then(() => {
            return downloadURL;
        }).catch((error) => {
            // Handle error
        })
});

Note that the above code does not use async/await.请注意,上面的代码没有使用 async/await。 If you want to use async/await, do as follows:如果要使用 async/await,请执行以下操作:

exports.getDownloadUrl = functions.https.onCall(async (data, context) => {

    try {
        const docRef = db.collection('projects').doc(data.docId);

        const doc = await docRef.get();
        const downloadURL = doc.data().downloadURL;

        const userRef = db.collection('customers').doc(context.auth.uid);
        await userRef.update({
            availableDownloads: admin.firestore.FieldValue.increment(-1)
        })

        return downloadURL;
    } catch (error) {
        // Handle error
    }

});

You can see that with this code, due to the fact that it is simplified by using async/await, there is no more complexity due to variable scoping.您可以看到,使用此代码,由于使用 async/await 对其进行了简化,因此不会因为变量作用域而变得更加复杂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM