这实际上是 Cloud Functions 的一个很好的使用示例。
将消息保存到数据库时,您可以使用ServerValue.TIMESTAMP 自动插入 Firebase 服务器的时间戳,因此您可以执行以下操作:
public void saveMessage(String content) {
DatabaseReference messagesRef = FirebaseDatabase.getInstance().getReference("messages");
HashMap<String, Object> message = new HashMap<>();
message.put("content", content);
message.put("startTime", ServerValue.TIMESTAMP);
messagesRef.push().setValue(message);
}
然后您可以将云函数附加到messages 位置以侦听新数据。此函数可以执行将 startTime 值添加 10 小时并将其保存为 endTime 回同一个孩子的逻辑,类似于:
exports.calculateEndTime = functions.database
.ref('/messages/{messageId}').onCreate(event => {
const message = event.data.val();
// Only calculate endTime if it doesn't already exist.
if (message && !message.endTime) {
// Add 10 hours (in milliseconds) to the startTime to obtain the endTime.
const endTime = message.startTime + (10 * 3600000);
// Update the Firebase Database with the new endTime value.
return event.data.adminRef.update({
endTime: endTime
});
}
});
最后,要查询消息列表以仅获取 endTime 尚未通过的消息,您可以执行以下操作:
// Obtain the server time using the .info/serverTimeOffset value.
DatabaseReference offsetRef = FirebaseDatabase.getInstance().getReference(".info/serverTimeOffset");
offsetRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
// Calculate the estimated server time based on the offset.
double offset = snapshot.getValue(Double.class);
double estimatedServerTimeMs = System.currentTimeMillis() + offset;
// Use this server time to get the messages.
getMessages(estimatedServerTimeMs);
}
@Override
public void onCancelled(DatabaseError error) { }
});
public void getMessages(double endTime) {
DatabaseReference messagesRef = FirebaseDatabase.getInstance().getReference("messages");
// Create a query to limit results where endTime is greater than the current time.
Query messagesQuery = messagesRef.orderByChild("endTime").startAt(endTime);
messagesRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot message : dataSnapshot.getChildren()) {
// ...
}
}
@Override
public void onCancelled(FirebaseError firebaseError) { }
});
}
此示例首先获取clock skew value (from .info/serverTimeOffset) 以计算估计的当前服务器时间,然后在startAt() 查询中使用它以仅在当前时间之后返回带有endTime 的消息。
可能还有其他一些方法可以解决此问题,例如获取服务器时间戳并在保存消息的同时执行上述逻辑,或者甚至只是查询startTime(10 小时前使用startAt)。
但是,使用 Cloud Functions 路由是确保在服务器端计算 endTime、快速保存新消息并且消息实际上在数据库中包含 endTime 值的好方法。