Firebase 函数接收对象而不是字符串
Posted
技术标签:
【中文标题】Firebase 函数接收对象而不是字符串【英文标题】:Firebase Functions receive Object instead of String 【发布时间】:2020-01-14 21:04:15 【问题描述】:忍受我。我花了一个月的时间来回答这个问题:我已经使用 Firebase 数据库和 Firebase 函数大约一年了。我已经让它工作了......但前提是我将消息文本作为字符串发送。问题是现在我希望收到一个 OBJECT,但我不确定如何在 FireBaseMessage 中执行此操作。
我之前的结构:
messages
T9Vh5cvUcbqC8IEZowBpJC3
ZWfn7876876ZGJeSNBbCpPmkm1
message
"messages":
".read": true,
"$receiverUid":
"$senderUid":
"$message":
".read": true,
".write": "auth.uid === $senderUid"
我的监听器功能是这样的:
exports.sendMessage = functions.database.ref('/messages/receiverUid/senderUid/message')
这是有问题的......出于各种原因。也就是说,如果旧消息是“嘿”,然后同一个人再次写“嘿”……那么原来的消息就会被覆盖。
所以我的新结构更像这样:
messages
-LkVcYqJoEroWpkXZnqr
body: "genius grant"
createdat: 1563915599253
name: "hatemustdie"
receiverUid: "TW8289372984KJjkhdsjkhad"
senderUid: "yBNbs9823789KJkjahsdjkas"
具体写成:
mDatabase.child("messages").push().setValue(message);
...我只是不确定如何写出那个函数。
我的意思是......理想情况下......它会是这样的:
exports.sendMessage = functions.database.ref('/messages/receiverUid/senderUid/msgID/msgOBJECT')
...但我只是不确定 Firebase 函数是如何读取这个新结构的。
现在我像这样推送到数据库:
mDatabase.child("messages").child(guid).child(user_Id).push().setValue(msgObject).addOnSuccessListener(this, new OnSuccessListener<Void>()
@Override
public void onSuccess(@NonNull Void T)
Log.d("MessageActivity", "Message Sent");
基本上我只想接收消息对象...其中包含所有内容...当它从通知到达时...并且能够轻松解析正文、日期、用户 ID 等。
有人能解释一下解决这个问题的正确方法吗?
UPATE应要求提供完整的云功能:
exports.sendMessage = functions.database.ref('/messages/receiverUid/senderUid/msgId/message')
.onWrite(async (change, context) =>
const message = context.params.message;
// const messageId = context.params.messageId;
const receiverUid = context.params.receiverUid;
const senderUid = context.params.senderUid;
// If un-follow we exit the function.
if (!change.after.val())
return console.log('Sender ', senderUid, 'receiver ', receiverUid, 'message ', message);
console.log('We have a new message: ', message, 'for: ', receiverUid);
// Get the list of device notification tokens.
const getDeviceTokensPromise = admin.database()
.ref(`/users/$receiverUid/notificationTokens`).once('value');
// Get the follower profile.
const getSenderProfilePromise = admin.auth().getUser(senderUid);
// The snapshot to the user's tokens.
let tokensSnapshot;
// The array containing all the user's tokens.
let tokens;
const results = await Promise.all([getDeviceTokensPromise, getSenderProfilePromise]);
tokensSnapshot = results[0];
const sender = results[1];
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren())
return console.log('There are no notification tokens to send to.');
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
console.log('Fetched sender profile', sender);
// console.log('David you're looking for the following UID:', followerUid);
// Notification details.
const payload =
notification:
title: `$sender.displayName sent you a message.`,
body: message,
tag: senderUid
,
// 'data': 'fuid': followerUid
data:
type: 'message',
name: sender.displayName
;
console.log('David you are looking for the following message:', message);
// Listing all tokens as an array.
tokens = Object.keys(tokensSnapshot.val());
// Send notifications to all tokens.
const response = await admin.messaging().sendToDevice(tokens, payload);
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) =>
const error = result.error;
if (error)
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered')
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
);
return Promise.all(tokensToRemove);
);
【问题讨论】:
展示你完整的云功能 刚刚贴在上面。 @YashKrishan 【参考方案1】:由于您现在将发送者和接收者的 UID 存储在消息中,因此您的云函数的声明将需要更改。
而不是这个:
exports.sendMessage = functions.database.ref('/messages/receiverUid/senderUid/msgId/message').onWrite(async (change, context) =>
您需要触发:
exports.sendMessage = functions.database.ref('/messages/messageId').onWrite(async (change, context) =>
因此,通过此更改,您的代码将在写入 /messages
的每条消息上触发。
现在您“只”需要获取发送者和接收者的 UID。由于您不再可以从context
获取它们,您将改为从change
获取它们。具体来说,change.after
包含数据库中存在的数据快照在写入完成之后。因此(只要您不删除数据),您可以通过以下方式获取 UID:
const receiverUid = change.after.val().receiverUid;
const senderUid = change.after.val().senderUid;
当然,你也会从那里得到实际的信息:
const message = change.after.val().message;
并且以防万一您需要消息 ID(它在数据库中写入的 -L...
键):
const messageId = change.after.val().messageId;
【讨论】:
哇...我不知道其他人是怎么想出来的。现在检查。稍后会报告! @YashKrishan 您的解决方案也是正确的,因此我对此表示赞同。当我们都按下回车键时,我只是输入了更多内容。 :) @mysticcola 我从documentation on Realtime Database triggers 获得了大部分信息,并通过查看functions-samples
repo,这是一个伟大的代码示例的宝库。
完全理解并感谢。但是,我怀疑 OP 在 RTD 中构建对象的方式。这是在这么多层中构建它的正确方法吗:/messages/receiverUid/senderUid/msgId/message?
我有一种感觉,这绝对不是一个好习惯。减少层有助于更多地处理 JSON 等格式的数据。【参考方案2】:
您只需要在 messageId 上触发:
exports.sendMessage = functions.database.ref('/messages/messageId').onWrite((change, context) =>
const changedData = change.after.val(); // This will have the complete changed data
const message = change.after.val().message; // This will contain the message value
......
);
详细说明弗兰克的回答:
您无法从 const message = context.params.message;
这样的上下文中获取数据,因为上下文中不再存在这些参数。
【讨论】:
这是否意味着我也必须更改 java ? (mDatabase.child("messages").child(guid).child(user_Id).push().setValue(message)) 还有可能还有上面定义的数据库结构? 不,我猜不是因为您已经修改了该代码以适应新格式。 我将其更改为“mDatabase.child("messages").push().setValue(message)”。它有点干净。此外,它更好地匹配:functions.database.ref('/messages/messageId')。感谢您的所有帮助! 你不会碰巧知道如何从“push()”获取 id 吧?它以前工作过......但现在 mDatabase2 = FirebaseDatabase.getInstance().getReference("messages"); mDatabase2.getKey() 只返回“消息”而不是实际的键。 一种方法是首先像这样存储密钥:***.com/a/43362516/8259771 然后使用它。以上是关于Firebase 函数接收对象而不是字符串的主要内容,如果未能解决你的问题,请参考以下文章
当使用多个规则时,规则应该返回一个字符串或布尔值,而不是接收到的“对象”
如何让我的 Amazon Redshift UDF 接收字符串而不是列表?
在 Firebase 中插入 JSON 显示为字符串,而不是显示为树