几个星期以来,我遇到了以下问题(以前不是问题):
const saveNewDoc = functions.https.onCall((data: NewDocWrite, context: CallableContext) => {
return adminDb
.collection(data.collectionPath)
.add(data.data)
})
文档已成功创建,但仍然向客户端返回错误“ INTERNAL”,并在功能日志中列出:
Unhandled error RangeError: Maximum call stack size exceeded
at baseIteratee (/srv/node_modules/lodash/lodash.js:3464:26)
at getIteratee (/srv/node_modules/lodash/lodash.js:5932:33)
at Function.map (/srv/node_modules/lodash/lodash.js:9556:31)
at encode (/srv/node_modules/firebase-functions/lib/providers/https.js:236:18)
at /srv/node_modules/lodash/lodash.js:13402:38
at /srv/node_modules/lodash/lodash.js:4911:15
at baseForOwn (/srv/node_modules/lodash/lodash.js:2996:24)
at Function.mapValues (/srv/node_modules/lodash/lodash.js:13401:7)
at encode (/srv/node_modules/firebase-functions/lib/providers/https.js:242:18)
at /srv/node_modules/lodash/lodash.js:13402:38
用add()
替换doc().set()
可以创建文档而没有任何错误。
知道为什么会这样吗?仅使用doc()。set()即可轻松实现“变通方法”,但我不知道为什么还要添加()。我们不能只对任何新文档使用doc()。set()吗?
答案 0 :(得分:0)
使用set
,您选择一个文档(分配自己的ID),add
,您让Firestore为您分配ID。
这里有一个很小的(不是那么小的)细节,您的可调用函数应返回一个承诺,该承诺将与响应一起解析以发送给客户端,您的函数将返回一个对数据库进行操作后已解决的承诺。
您的代码抱怨的那一行看起来像这样:
if (_.isArray(data)) {
return _.map(data, encode);
}
与您使用的方法相比,我将更加关注发送的数据。
const saveNewDoc = functions.https.onCall(async (data: NewDocWrite, context: CallableContext) => {
await adminDb.collection(data.collectionPath).add(data.data)
// OR
await adminDb.collection(data.collectionPath).doc().set(data.data)
return Promise.resolve({ ok: true })
})
实际上,doc().set()
等效于.add()
,我通常使用set
,因为我希望可以控制要设置的文档ID,但也可以将其保留为空。尝试这样做,避免对数据库exec返回promise应该很好。
答案 1 :(得分:0)
我发现的原因很简单:
add()
返回Promise<FirebaseFirestore.DocumentReference>
的同时
set()
返回“承诺”
添加新文档的操作可以以任何一种方式进行,但是一旦完成,响应就会被发送回客户端,文档引用或写在Promise中的结果都将返回给客户端。由于响应中仅允许使用有效的JSON,因此返回文档引用将导致错误,因为该引用不是有效的JSON格式。
因此,一旦操作完成,请解析一个空的Promise或将结果转换为有效的JSON,然后再将其包装在响应中-或使用set()。