【问题标题】:Can't access Firestore docs data after getting the doc object获取文档对象后无法访问 Firestore 文档数据
【发布时间】:2021-08-25 15:03:08
【问题描述】:

我正在尝试从集合(存储在 Firestore)中的文档中获取单个字段值。 (由触发的函数)调用以下函数来执行此查询并返回结果。

Firestore 数据结构:

将查询结果提取到 helper_token 对象后 - 我无法访问其中的 DATA(字段)。 我尝试了很多东西,包括:

helper_token[0].device_token;
helper_token.data().device_token;
JSON.stringify(helper_token);

没有什么对我有用。 日志总是显示如下结果:

helper_token = {}
helper_token = undefined

我错过了什么? 如何根据user 获得device_token

const admin = require('firebase-admin'); //required to access the FB RT DB
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();

function getHelperToken(helperId) {
    //Get token from Firestore
    const tokensRef = db.collection('tokens');
    const helper_token = tokensRef.where('user', '==', 'TM1EOV4lYlgEIly0cnGHVmCnybT2').get();
    if (helper_token.empty) {
        functions.logger.log('helper_token EMPTY');
    }
    functions.logger.log('helper_token=' + JSON.stringify(helper_token));

    return helper_token.device_token;
};

为了完整起见,在此处将完整的调用函数添加到上述函数中:

//DB triggered function - upon writing a child in the HElpersInvitations reference
exports.sendHelperInvitation = functions.database.ref('/HelpersInvitations/{helper_invitation_id}')
    .onCreate((snapshot, context) => {

        const helperId = snapshot.val().helperId;
        const title = snapshot.val().title;
        const body = snapshot.val().body;
        
        //Get the helper token by Id
        functions.logger.log('HelperID=' + helperId);
        functions.logger.log('getHelperToken=' + getHelperToken(helperId));
        const helper_token2 = getHelperToken(helperId);
        //Notification payload
        const payload = {
            notification: {
                title: title,
                body: body,
                icon: 'default',
                click_action: 'com.skillblaster.app.helperinvitationnotification' 
            }
        }
        
        //    //Send the notification
            functions.logger.log('helper_token [BEFORE sendToDevice]=' + helper_token2);
            return admin.messaging().sendToDevice(helper_token2, payload);


    });

【问题讨论】:

    标签: google-cloud-firestore


    【解决方案1】:

    您需要考虑get() 调用是异步的,并且您获得的是文档列表而不是单个doc。你能用这段代码试试吗:

    const admin = require("firebase-admin"); //required to access the FB RT DB
    admin.initializeApp(functions.config().firebase);
    const db = admin.firestore();
    
    async function getHelperToken(helperId) {
      //Get token from Firestore
      const tokensRef = db.collection("tokens");
      const helperTokens = await tokensRef
        .where("user", "==", "TM1EOV4lYlgEIly0cnGHVmCnybT2")
        .get();
      let helper_token = "";
    
      helperTokens.forEach((token) => {
        helper_token = token.data();
      });
    
      functions.logger.log("helper_token=" + JSON.stringify(helper_token));
    
      return helper_token.device_token;
    }
    
    

    【讨论】:

    • 谢谢!不幸的是,这个函数的异步特性不会及时向调用函数返回任何内容。甚至没有到达记录器语句。
    • 如何调用函数?
    • const helper_token2 = getHelperToken(helperId); - 查看对原始问题的编辑以获取完整的调用函数代码
    • 你需要这样称呼它helper_token2 = await getHelperToken(helperId);
    • 谢谢你,塔里克。但是 await 仅在异步函数中可用。这是一个 DB 触发的函数。
    【解决方案2】:

    由于 Firestore 中的 get() 调用是异步的,您需要使用异步函数。您可以通过this article 了解有关 Firebase API 为何是异步的更多信息。接下来,当我们在 Firestore 中使用 where 子句进行查询时,我们会得到一个文档列表,即使列表中只有一个文档。所以我们必须运行一个 for 循环来获取文档列表中的文档。现在,当您从异步函数返回值时,返回值将是处于挂起状态的承诺。因此,要从 Promise 中获取值,我们需要在调用函数时使用 then() 块。

    另外我认为你在函数定义中使用的参数helperId 没有在函数的任何地方使用。虽然它不会有什么不同,但如果函数中不需要它,我建议你删除它。

    所以考虑使用下面的代码-

    const admin = require(‘firebase-admin’);
    admin.initializeApp(functions.config().firebase);
    const db = admin.firestore();
     
    async function getHelperToken() {
       //Get token from Firestore
       const tokensRef = db.collection(‘tokens’);
       const helper_token = await tokensRef.where(‘user’, ‘==’, ‘TM1EOV4lYlgEIly0cnGHVmCnybT2’).get();
     
       let helper_token_needed;
       helper_token.forEach((token) => {
         helper_token_needed = token.data();
       });
        console.log(helper_token_needed.device_token);
       return helper_token_needed.device_token;
     }
     
    //when calling to the function use then() block to get the value as a promise is returned from asynchronous function
    getHelperToken().then((value)=>{console.log(value)});
    

    【讨论】:

    • 谢谢普拉比尔。我使这个函数异步,但调用函数不是异步的(它是由 DB 触发的 - 见上文),因此我不能在那里使用“等待”。顺便说一句,helperId 参数将替换“where”查询中的硬编码 ID。
    • 感谢您编辑问题并澄清helperId 的使用。您能否确认您是否在任何地方使用数据库触发函数的返回值。或者只打电话给admin.messaging().sendToDevice(helper_token2, payload) 会做你的工作?
    猜你喜欢
    • 1970-01-01
    • 2018-09-03
    • 2019-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多