我使用 Firebase 作为 iOS 应用的后端,但不知道如何通过其云函数构建批量写入。
我的 Firestore 中有两个集合:饮料和顾客。每个新饮料和每个新客户都会分配一个 userId
属性,该属性与当前登录用户的 uid 相对应。此 userId
与对 Firestore 的查询一起使用,以仅获取与登录用户相关的饮料和客户,如下所示:Firestore.firestore().collection("customers")。 whereField("userId", isEqualTo: Auth.auth().currentUser.uid)
用户可以匿名登录,也可以匿名订阅。问题是,如果他们注销,就无法重新登录到同一个匿名 uid。 uid 还通过 RevenueCat SDK 存储为 appUserID
,因此我仍然可以访问它,但由于我无法使用 uid 将用户重新登录到其匿名帐户,这是帮助用户的唯一方法。用户在恢复购买时访问其数据的方法是将其数据的 userId
字段从旧 uid 更新为新 uid。这就是需要批量写入的地方。
总的来说,我对编程还比较陌生,但对于 Cloud Functions、JavaScript 和 Node.js 来说,我非常新鲜。不过,我在网络上进行了研究,认为我找到了一个解决方案,可以创建一个可调用的云函数,并使用数据对象发送新旧用户 ID,查询具有旧用户 ID 的文档集合并更新其 userId
字段到新的。不幸的是它不起作用,我不明白为什么。
这是我的代码:
// Cloud Function
exports.transferData = functions.https.onCall((data, context) => {
const firestore = admin.firestore();
const customerQuery = firestore.collection('customers').where('userId', '==', `${data.oldUser}`);
const drinkQuery = firestore.collection('drinks').where('userId', '==', `${data.oldUser}`);
const customerSnapshot = customerQuery.get();
const drinkSnapshot = drinkQuery.get();
const batch = firestore.batch();
for (const documentSnapshot of customerSnapshot.docs) {
batch.update(documentSnapshot.ref, { 'userId': `${data.newUser}` });
};
for (const documentSnapshot of drinkSnapshot.docs) {
batch.update(documentSnapshot.ref, { 'userId': `${data.newUser}` });
};
return batch.commit();
});
// Call from app
func transferData(from oldUser: String, to newUser: String) {
let functions = Functions.functions()
functions.httpsCallable("transferData").call(["oldUser": oldUser, "newUser": newUser]) { _, error in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
print(code)
print(message)
print(details)
}
}
}
}
这是来自 Cloud Functions 日志的错误消息:
Unhandled error TypeError: customerSnapshot.docs is not iterable
at /workspace/index.js:22:51
at fixedLen (/workspace/node_modules/firebase-functions/lib/providers/https.js:66:41)
at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:385:32
at processTicksAndRejections (internal/process/task_queues.js:95:5)
据我了解,customerSnapshot
是一种称为 Promise 的东西,我猜这就是我无法迭代它的原因。到目前为止,我的知识太深了,不知道如何处理查询返回的这些 Promise。
我想我可以强制用户在订阅之前创建一个登录名,但既然我已经走到了这一步,这感觉就像是一个懦夫的出路。我宁愿同时拥有这两种选择并做出决定,而不是走一条被迫的道路。另外,如果我弄清楚了这一点,我将学习更多 JavaScript!
非常感谢任何和所有帮助!
编辑:
解决方案:
// Cloud Function
exports.transferData = functions.https.onCall(async(data, context) => {
const firestore = admin.firestore();
const customerQuery = firestore.collection('customers').where('userId', '==', `${data.oldUser}`);
const drinkQuery = firestore.collection('drinks').where('userId', '==', `${data.oldUser}`);
const customerSnapshot = await customerQuery.get();
const drinkSnapshot = await drinkQuery.get();
const batch = firestore.batch();
for (const documentSnapshot of customerSnapshot.docs.concat(drinkSnapshot.docs)) {
batch.update(documentSnapshot.ref, { 'userId': `${data.newUser}` });
};
return batch.commit();
});
最佳答案
正如您已经猜到的,调用 customerQuery.get()
返回一个 promise 。
为了了解您需要什么,您应该首先熟悉这里的 Promise 概念:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
对于您的用例,您可能最终会使用 then
回调:
customerQuery.get().then((result) => {
// now you can access the result
}
或者通过使用 await
语句使方法调用同步:
const result = await customerQuery.get()
// now you can access the result
关于javascript - 使用 Firebase Cloud Functions 批量写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70747498/