Firebase函数异步方法返回未定义

时间:2020-03-26 12:55:47

标签: javascript firebase firebase-realtime-database google-cloud-functions

enter image description here

您好,我已经设置了Firebase功能,正在监视用户是否匹配。 所有部分都起作用,但是我又添加了一种方法 getUserDataById ,我想从用户那里获取更多数据,它返回未定义。 所以这就是我尝试过的:

exports.UserPressesLike = functions.database
  .ref('/users/{userId}/matches/{otherUserId}')
  .onCreate(async (snapshot, context) => {
    // Grab the current value of what was written to the Realtime Database.
    const original = snapshot.val();
    const userId = context.params.userId;
    const matchedUserId = context.params.otherUserId;
    const a = await checkUserMatch(userId, matchedUserId);
    if (a === true) {
      console.log('Its a match');
      addNewChat(userId, matchedUserId);
      //create chat for both users
    } else {
      console.log('There is no match');
      //do nothing
      console.log(a);
    }

    return null;
  });

checkUserMatch = async (userId, matchedUserId) => {
  const isLiked = await admin
    .database()
    .ref('/users/' + matchedUserId + '/matches/' + userId)
    .once('value')
    .then(snapshot => {
      // let tempuserId = snapshot.val();
      // if()
      let isLiked = snapshot.exists();
      console.log(isLiked);
      return isLiked;
    })
    .catch(error => {
      console.log(error);
      return snapshot;
    });
  return isLiked;
};

addNewChat = async (userId, matchedUserId) => {
  const user1 = await getUserDataById(userId);
  const user2 = await getUserDataById(matchedUserId);
  console.log(JSON.stringify('User data: ' + user1));
  const snapshot = await admin
    .database()
    .ref('/chats')
    .push({
      members: { [userId]: true, [matchedUserId]: true },
      [userId]: { username: [user1.username] },
      [matchedUserId]: { username: [user2.username] },
    });
};

getUserDataById = async userId => {
  const snapshot = await admin
    .database()
    .ref('/users/' + userId)
    .once('value')
    .then(childsnapshot => {
      let data = childsnapshot.val();
      return data;
    });
};

但是我得到了错误:

TypeError: Cannot read property 'username' of undefined
    at addNewChat (/srv/index.js:93:36)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:229:7)

问题出在getUserDataById方法中。因为它返回未定义。 我在哪里弄错了?

为什么我得到用户名:{0:emilis}它应该是用户名:emilis? enter image description here

1 个答案:

答案 0 :(得分:1)

第1部分:getUserDataById返回undefined

您在异步功能中忘记了return snapshot。 (但是,由于它是一个普通对象,而不是快照,因此我将其重命名)

getUserDataById = async userId => {
  const userData = await admin
    .database()
    .ref('/users/' + userId)
    .once('value')
    .then(childsnapshot => {
      let data = childsnapshot.val();
      return data;
    });
  return userData;
};

但是,我将其简化为以下内容(与上述内容相同,但简洁明了):

getUserDataById = userId => {
  return admin
    .database()
    .ref('/users/' + userId)
    .once('value')
    .then(childsnapshot => childsnapshot.val());
};

第2部分:为什么我的数据以{username: {0: "Emilis"}}的形式返回?

{0: "Emilis"}作为对象而不是数组返回是由Firebase在实时数据库中存储数组的方式引起的。在arrays on the Firebase Blog上有一篇非常全面的文章,涵盖了这些奇怪的地方,建议阅读。我将在这里总结关键的内容。

任何数组存储在实时数据库中时,将以其对象形式存储,其中{username: [user1.username] }将存储为{username: {0: "someusername"} }。由于JSON是无类型的,因此Realtime Database不再将其理解为数组。具有多个条目的数组也将存储为一个普通对象([value1, value2]将变成{0: value1, 1: value2})。

当Firebase JavaScript SDK从实时数据库下载数据时,它会检查任何对象的键以获取大部分为连续的数字序列(0、1、2、3,...或0、1、3、4,)。 ..),如果检测到,则使用null将其丢失的条目转换为数组。

由于{0: value1, 1: value2}包含顺序键01,因此它将解析为[value1, value2]

由于{0: "someusername"}不包含键序列,因此按原样返回。

要绕过此操作,请删除单个条目数组并直接使用其值(如下所示),或在客户端代码中将其显式转换为数组。

addNewChat = async (userId, matchedUserId) => {
  const user1 = await getUserDataById(userId);
  const user2 = await getUserDataById(matchedUserId);
  console.log(JSON.stringify('User data: ' + user1));
  return admin // don't forget to return the Promise!
    .database()
    .ref('/chats')
    .push({
      members: { [userId]: true, [matchedUserId]: true }, // FYI: these are "use value as the key" instructions not arrays.
      [userId]: { username: user1.username },
      [matchedUserId]: { username: user2.username },
    });
};