You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase云函数批量获取Firestore文档后Unity端解析异常问题

问题分析

1. 云函数侧核心错误

  • 直接把Firestore异步get返回的Promise对象存入数组返回,没有等待异步请求完成,也没有提取实际文档数据,返回给前端的是未完成的Promise序列化后的无效内容
  • 遍历groupMembers的QuerySnapshot时,直接取group.groupId是错误的,QueryDocumentSnapshot需要先调用.data()方法才可以拿到文档字段,正确写法是group.data().groupId
  • 额外语法错误:查询单用户文档的写法错误,collection('users').get(data.userid)是无效调用,查询单文档需要先指定doc,应为collection('users').doc(data.userid).get()(当前代码中userData未使用,可以直接删除)

2. Unity侧核心错误

Firebase HttpsCallable返回的集合类型默认是List<object>,其中每个元素是对应Firebase文档字段的Dictionary<string, object>,无法直接通过as List<Group>做类型转换,转换结果为null,所以foreach不会执行。

修复实现

第一步:修复云函数代码

exports.getUserData = functions.https.onCall(async(data, context) => {
    if (!context.auth) {
        throw new functions.HttpsError(
            'unauthenticated',
            'only authenticated users can make requests!'
        );
    }
    // 原无用的userData查询已删除
    const myGroupMemberships = await admin.firestore().collection('groupMembers').where("playerId", "==", data.userid).get();
    // 生成所有groups查询的Promise数组
    const groupPromises = myGroupMemberships.docs.map(async (groupDoc) => {
        const groupId = groupDoc.data().groupId;
        const groupSnapshot = await admin.firestore().collection('groups').doc(groupId).get();
        // 返回实际的文档数据而非Snapshot对象
        return groupSnapshot.data();
    });
    // 等待所有group查询完成再返回
    const myGroups = await Promise.all(groupPromises);
    return { "groups": myGroups };
});

第二步:修复Unity侧代码

首先确保你的Group类标记了序列化属性:

[System.Serializable]
public class Group
{
    public string groupName;
    // 补充其他和Firebase文档字段对应的属性
}

修改调用逻辑,手动转换返回的集合:

var func = FirebaseManager.instance.functions.GetHttpsCallable("getUserData");
var data = new Dictionary<string, object>();
data["userid"] = userId;

var task = func.CallAsync(data).ContinueWithOnMainThread((callTask) => {
    if (callTask.IsFaulted)
    {
        GA.Log("FAILED!");
        GA.Log(string.Format("  Error: {0}", callTask.Exception));
        return;
    }

    var result = (IDictionary)callTask.Result.Data;
    GA.Log(string.Format("Whats in the groups: {0}", result["groups"]));

    List<Group> theGroups = new List<Group>();
    // 先转成通用List<object>遍历
    var rawGroups = result["groups"] as List<object>;
    foreach (var rawGroup in rawGroups)
    {
        // 每个元素是存储字段的字典,手动映射为Group对象
        var groupDict = rawGroup as Dictionary<string, object>;
        Group newGroup = new Group();
        newGroup.groupName = groupDict["groupName"].ToString();
        // 补充其他字段赋值逻辑
        theGroups.Add(newGroup);
        
        GA.Log("GroupName: " + newGroup.groupName);
    }
});

yield return new WaitUntil(() => task.IsCompleted);

如果字段较多不想手动赋值,也可以先把groupDict序列化为JSON字符串,再通过JsonUtility.FromJson<Group>()直接反序列化为Group对象。

内容的提问来源于stack exchange,提问作者Mansa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 10:12:03