javascript - Firebase Firestore - 复合查询中包含多个数组

标签 javascript node.js firebase google-cloud-firestore nosql

介绍
我正在向我的应用程序添加一个聊天(没有群组,只有个人聊天(2 个用户之间)),如果一个用户删除了他与其他用户的完整聊天,两个用户都将无法阅读他们之前的对话,喜欢发生在 Telegram 上。
数据库模型
在这个用例中,我根本不需要数据库非规范化。
这是我的 NoSql 模型:

usernames/ (collection) 
     jack/ (document)
         -userId: "41b932028490"
     josh/ (document)
         -userId: "212930294348"

users/ (collection)
     41b932028490/ (document)
         -avatar: {uri}
         -username: jack
         -...other data
     212930294348/ (document)
         -avatar: {uri}
         -username: "josh"
         -...other data

chats/ (collection)
      chatId/ (document) <------------ (Some kind of chat room)
           -members: ["41b932028490", "212930294348"]
           messages/ (sub-collection)
               message1Id/ (document)
                   -userId: "41b932028490" // sender
                   -type: "text" 
                   -text: "hello world!"

               message2Id/ (document)
                   -userId: "41b932028490" // sender
                   -type: "GIF"
                   -uri: "https://media.giphy.com/media/HP7mtfNa1E4CEqNbNL/giphy.gif"
问题
我遇到的问题是创建聊天室的逻辑。如您所见,我有一个字段“成员”,其中包含两个用户的 ID。我想做的只是进行查询并尝试在聊天集合中找到两个用户(消息的发送者和消息的接收者)都是成员的房间。如果房间存在,我只需要添加消息。如果没有,我将不得不使用新的第一条消息创建房间。
例如,如果用户“Jack”要向用户“Josh”发送第一条消息(聊天室尚不存在),则服务器将首先创建一个聊天室(两个用户都是成员),并且新的第一条消息作为数据。
但是...如果两个用户同时发送消息会发生什么? (不一致:可能会创建 2 个聊天室)。为了避免这些不一致,我在数据库事务中原子地运行这个逻辑,如下所示:
await firestore.runTransaction((transaction) => {
      // Does the chat room exists in the chats' collection?
      const chatsRef = firestore.collection("chats");
      return chatsRef
        .where("members", "array-contains", fromId) <--------- PROBLEM!
        .where("members", "array-contains", toId) <----------- PROBLEM!
        .limit(1)
        .get()
        .then((snapshot) => {
          if (!snapshot.empty) {
            // If yes, add the message to the chat room
            const chatRoom = snapshot.docs[0];
            const chatRoomPath = chatRoom.ref.path;
            const newMessageRef = firestore
              .doc(chatRoomPath)
              .collection("messages")
              .doc(); // Auto-generated uuid

            const newMessageData = {
              userId: fromId,
              message,
              date: admin.firestore.FieldValue.serverTimestamp(),
            };

            transaction.set(newMessageRef, newMessageData);
          } else {
            // TODO - Check that the receiver exists in the database (document read)
            // TODO - If exists -> create chat room with the new message
            // TODO - If not exists -> throw error
          }

          // TODO - Increment the chat counter for the receiver when adding the message
        });
    });
但是,文档说

you can include at most one array-contains or array-contains-any clause in a compound query.


这就是我卡住的地方,因为我需要找到一个房间,两个用户都是成员......我能想到的唯一另一种方法是执行两个查询(一个 OR)
 where("member1", "==", fromId).where("memeber2", "==", toId)

 // and

 where("member1", "==", toId).where("memeber2", "==", fromId)
如何使用单个查询进行此操作?有任何想法吗?
谢谢你。

最佳答案

我建议您在聊天文档中创建一个额外的字段,例如连接两个用户 ID。您可以在创建聊天室的同一事务中或使用 firebase 函数来完成。
这将简化查询,因为您只需搜索这个新字段:

where("membersconcat", "==", fromId+toId)
我花了一段时间才接受这些额外的字段,但它确实避免了很多与 firestore 查询限制的斗争

关于javascript - Firebase Firestore - 复合查询中包含多个数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65697634/

相关文章:

ios - 手动屏幕跟踪在 Firebase (iOS) 中不起作用

firebase - 已删除的用户有权访问 Firebase Firestore

angular - 在 Firebase 上托管 Angular 项目

javascript - html 表单提交中 "required"关键字的错误处理

javascript - Java 中的圆周调试

node.js - Express 未捕获中间件中的异常

javascript - if语句中的Ejs无法读取未定义的属性 ' foo '

javascript - node.js - 代码保护?

php - 类型错误:$(...) 不是函数

javascript - 如何使用 JavaScript 设置 CSS 值?