使用 Firebase Cloud Functions 批量写入
Batch write with Firebase Cloud Functions
我正在使用 Firebase 作为我的 iOS 应用程序的后端,但不知道如何通过他们的 Cloud Functions 构建批量写入。
我的 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。这就是需要批量写入的地方。
总的来说,我对编程还比较陌生,但在云函数方面我非常新鲜,JavaScript 和 Node.js。我在网上四处游荡,认为我找到了一个解决方案,我创建了一个可调用的 Cloud Function 并将新旧用户 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()
returns 一个承诺。
为了理解你需要什么,你应该首先在这里熟悉承诺的概念: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
我正在使用 Firebase 作为我的 iOS 应用程序的后端,但不知道如何通过他们的 Cloud Functions 构建批量写入。
我的 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。这就是需要批量写入的地方。
总的来说,我对编程还比较陌生,但在云函数方面我非常新鲜,JavaScript 和 Node.js。我在网上四处游荡,认为我找到了一个解决方案,我创建了一个可调用的 Cloud Function 并将新旧用户 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()
returns 一个承诺。
为了理解你需要什么,你应该首先在这里熟悉承诺的概念: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