根据用户的 uid 生成 Firestore 文档的文档 ID



在我的聊天应用程序中,我可以在两个用户之间进行私人聊天。我打算使用这两个用户的docId/uid来设置聊天文档的id,这样它就不取决于它们的组合顺序,并且我可以使用用户的uid来确定聊天文档的docId,而不管uid的顺序如何。

我知道,我也可以使用where子句来获取聊天文档。我生成聊天文档的docId的方法有什么重大缺陷吗?我应该让它自动生成并使用firestore和limit(1(支持的正常where子句来获得聊天吗?

基本上,我想要的是加密uid1,使其只返回一个数字,然后与uid2相同,然后将它们相加以创建ChatId。这样,它就不取决于我添加它们的顺序,我可以获得chatId,并可能使用Base64编码将该数字转换回字符串。这样,如果我知道参与聊天的用户,我就可以生成相同的聊天ID。这行得通吗?还是有缺陷?

将每个用户ID转换为一个数字,然后将它们相加可能会导致冲突。作为一个简单的例子,考虑一下可以将数字5相加的多种方法:0+51+42+3

这个答案建立在@NimnaPerera的答案之上。

方法1:<uid>_<uid>

如果你的应用程序不打算使用大型组,你可以使用<uid>_<uid>格式。为了确保两个用户ID以相同的方式排序,可以先对它们进行排序,然后使用一些分隔符将它们组合在一起。

实现这一点的一个简单方法是使用:

const docId = [uid1, uid2].sort().join("_");

如果你想进行三方群聊,你只需要在数组中添加新的用户ID:

const docId = [uid1, uid2, uid3].sort().join("_");

你也可以把它变成一种可读性的方法:

function getChatIdForMembers(userIds) {
return userIds.sort().join("_");
}

下面是一个实际应用的例子:

const uid1 = "apple";
const uid2 = "banana";
const uid3 = "carrot";
[uid1, uid2].sort().join("_"); // returns "apple_banana"
[uid1, uid3].sort().join("_"); // returns "apple_carrot"
[uid2, uid1].sort().join("_"); // returns "apple_banana"
[uid2, uid3].sort().join("_"); // returns "banana_carrot"
[uid3, uid1].sort().join("_"); // returns "apple_carrot"
[uid3, uid2].sort().join("_"); // returns "banana_carrot"
// chats to yourself are permitted
[uid1, uid1].sort().join("_"); // returns "apple_apple"
[uid2, uid2].sort().join("_"); // returns "banana_banana"
[uid3, uid3].sort().join("_"); // returns "carrot_carrot"
// three way chat
[uid1, uid2, uid3].sort().join("_"); // returns "apple_banana_carrot"
[uid1, uid3, uid2].sort().join("_"); // returns "apple_banana_carrot"
[uid2, uid1, uid3].sort().join("_"); // returns "apple_banana_carrot"
[uid2, uid3, uid1].sort().join("_"); // returns "apple_banana_carrot"
[uid3, uid1, uid2].sort().join("_"); // returns "apple_banana_carrot"
[uid3, uid2, uid1].sort().join("_"); // returns "apple_banana_carrot"

方法2:成员列表属性

如果你打算支持群聊,你应该使用自动文档ID(请参阅CollectionReference#add()(,并将聊天成员列表存储为其字段之一,如@NimnaPerera的回答中所述,以更好地使用查询。

我推荐两个字段:

  • "members"-一个包含每个聊天成员ID的数组。这允许您在/chats集合中查询包含给定用户的聊天
  • "membersAsString"-一个字符串,通过对"members"进行排序并使用"_"连接它们而构建。这允许您在/chats集合中查询包含确切成员列表的聊天
"chats/{chatId}": {
"members": string[], // list of users in this chat
"membersAsString": string, // sorted list of users in this chat, delimited using "_"
/* ... */
}

查找我参与的所有聊天:

const myUserId = firebase.auth().currentUser.uid;
const myChatsQuery = firebase.firestore()
.collection("chats")
.where("members", "array-contains", myUserId);
myChatsQuery.onSnapshot(querySnapshot => {
// do something with list of chat documents
});

查找苹果、香蕉和我之间的所有三方聊天:

const myUserId = firebase.auth().currentUser.uid;
const members = [myUserId, "banana", "apple"];
const membersAsString = members.sort().join("_");
const groupChatsQuery = firebase.firestore()
.collection("chats")
.where("membersAsString", "==", membersAsString);
groupChatsQuery.onSnapshot(querySnapshot => {
// do something with list of chat documents
// normally this would return 1 result, but you may get
// more than one result if a user gets added/removed a chat
});

一个正常的流程,将是:

  1. 获取相关聊天的列表
  2. 每次聊天,获取最新消息
  3. 根据最近的消息,对UI中的聊天进行排序

只要遵守以下约束,就可以很好地使用两个用户uid的组合来定义Firestore文档ID:

  • 必须是有效的UTF-8字符
  • 必须不超过1500字节
  • 不能包含正斜杠(/(
  • 不能仅由单周期(.(或双周期(..(组成
  • 无法匹配正则表达式__.*__

在你的问题中我不确定能理解的是";以这样一种方式,它不取决于它们组合的顺序";。如果您组合两个用户的uid,则需要按特定顺序组合它们。例如,uid1_uid2不等于ui2_uid1

当你询问@lightsaber时,你可以按照以下方法来实现你的目标。但我个人更喜欢使用where子句,因为firestore支持在实时数据库中无法完成的复合查询。

方法1

创建一个支持功能来生成聊天id,并根据该id检查文档是否存在。然后,您可以创建聊天文档或使用该id检索文档。

const getChatId = (currentUserId: string, guestUserId: string) => {
/* In this function whether you changed the order of the values when passing as parameters
it will always return only one id using localeCompare */

const comp = currentUserId.localeCompare(guestUserId);
if (comp === 0) {
return null;
}
if (comp === -1) {
return currentUserId + '_' + guestUserId;
} else {
return guestUserId + '_' + currentUserId;
}
}

方法2

将where子句与array-contains查询一起用于检索聊天文档。创建时,将两个用户ID添加到数组中,并使用相关字段名设置数组。

用于查询阵列的Firestore文档

最新更新