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
相关产品推荐
相关产品推荐

