2016-11-17 5 views
19

구조는 다음중포 기지 쿼리 경우 테이블의

  • 채팅
  • -> randomId
  • -> -> 참가자
  • -> - -> -> 0 : "NAME1"
  • -> -> -> 1 : "NAME2"
  • -> -> chatItems

내가하려는 것은 채팅 테이블을 쿼리하여 전달 된 사용자 이름 문자열로 참가자를 보유하는 모든 채팅을 찾는 것입니다.

subscribeChats(username: string) { 
    return this.af.database.list('chats', { 
     query: { 
      orderByChild: 'participants', 
      equalTo: username, // How to check if participants contain username 
     } 
    }); 
} 

답변

32

여기에 몇 가지 문제 : 당신이 고정에 배열

  • 당신이 할 수있는 유일한 지표로 설정 저장하고

    • 여기

      는 내가 지금까지 무엇을 가지고 경로

    대 vs 배열

    채팅에는 여러 참가자가있을 수 있으므로이 사람을 배열로 모델링했습니다. 그러나 이것은 실제로 이상적인 데이터 구조가 아닙니다. 각 참가자는 한 번만 채팅에 참여할 수 있습니다. 그러나 배열을 사용하여, 나는 할 수 :

    participants: ["puf", "puf"] 
    

    당신이 마음이 무엇인지 명확하지 않지만 데이터 구조가 허용하는 그. 코드 및 보안 규칙에서이를 보호 할 수는 있지만 암시 적으로 모델을 더 잘 일치시키는 데이터 구조로 시작하는 것이 더 쉽습니다.

    내 경험칙 : 자신이 array.contains()을 작성하는 경우 세트를 사용해야합니다.

    집합은 각 자식이 최대 한 번만 존재할 수있는 구조이므로 자연스럽게 중복으로부터 보호됩니다.

    participants: { 
        "puf": true 
    } 
    

    여기 true는 정말 그냥 더미 값이다 :로 중포 기지에서는 집합을 모델링하려는 중요한 것은 우리가 키에 이름을 이동 한 것입니다. 내가 다시 채팅에 참여하려고 줄 이제 경우, 그것은 무 조작 될 것이다 :

    participants: { 
        "puf": true 
    } 
    

    그리고 당신은 가입 줄 때

    participants: { 
        "john": true, 
        "puf": true 
    } 
    

    이 귀하의 요구 사항에 가장 직접적인 표현하십시오 한 번만 각 참가자를 포함 할 수있는 컬렉션.

    에만 인덱스 고정 경로 상기 구성

    , 당신은 당신이에있는 채팅을위한 질의 할 수 있습니다 : 당신이 인덱스를 정의보다

    ref.child("chats").orderByChild("participants/john").equalTo(true) 
    

    문제는이 요구된다 '참가자/존'에 대해 :

    { 
        "rules": { 
        "chats": { 
         "$chatid": { 
         "participants": { 
          ".indexOn": ["john", "puf"] 
         } 
         } 
        } 
        } 
    } 
    

    이 기능은 훌륭하게 작동합니다.하지만 새로운 사용자가 채팅 앱에 참여할 때마다 ' 다른 색인을 추가해야합니다. 그것은 분명히 확장 가능한 모델이 아닙니다. 원하는 쿼리를 허용하도록 데이터 구조를 변경해야합니다.

    반전 인덱스 - 트리에게 엄지 손가락의

    두 번째 규칙을 평평하게, 카테고리를 끌어 : 모델 데이터를 앱에 표시 것을 반영합니다.

    당신은, 사용자의 대화방 목록을 표시 각 사용자에 대해 대화방을 저장하기 위해 찾고 있기 때문에 :

    ref.child("userChatrooms").child("john") 
    
    :

    userChatrooms: { 
        john: { 
        chatRoom1: true, 
        chatRoom2: true 
        }, 
        puf: { 
        chatRoom1: true, 
        chatRoom3: true 
        } 
    } 
    

    지금 당신은 단순히와 대화방 목록을 확인할 수 있습니다

    그리고 각 방을 얻기 위해 열쇠를 반복하십시오.

    당신은 앱에서 두 개의 관련 목록이 좋아하는 것 :

    • 특정 사용자
    • 특정 채팅방에서 참가자의 목록 대화방 목록

    에서 이 경우 데이터베이스에 두 목록이 모두 표시됩니다.

    chatroomUsers 
        chatroom1 
        user1: true 
        user2: true 
        chatroom2 
        user1: true 
        user3: true 
    userChatrooms 
        user1: 
        chatroom1: true 
        chatroom2: true 
        user2: 
        chatroom1: true 
        user2: 
        chatroom2: true 
    

    Firebase가 데이터 중첩을 권장하므로 두 목록을 모두 트리의 최상위 수준으로 가져 왔습니다.

    두 목록을 모두 보유하면 NoSQL 솔루션에서 완전히 정상입니다. 위의 예에서 의 역 색인으로 userChatrooms을 참조했습니다.

  • +0

    이것은 대단한 설명입니다. 내 데이터를 이와 같이 저장 했으므로 사용자 목록에서 대화방을 움켜 잡거나 대화방의 구성원에게서 사용자를 확보 할 수 있습니다. 그러나 그것이 허용하지 않는 것은 내가 회원 인 대화방에 대한'.ChildChanged'를 관찰하는 것입니다. 'members/myId = true'라는 대화에 대한 관찰자를 설정하려고하면 불특정 색인 오류가 발생합니다. 어떻게 이것에 대해 가겠습니까? 나는 여기에 게시 된 질문이 있습니다 :https://stackoverflow.com/questions/47769044/swift-firebase-using-an-unspecified-index –

    +0

    마지막 코드 조각을 참조하는 @ frank-van-puffelen, "user1"이라고 가정 해 봅시다. "내가 회원 인 모든 회의실 열쇠를 가져옵니다. 그런 다음 각 chatroom 키에 대해 전체 chatroom 개체를 가져오고 대화방 목록을 목록에 표시합니다. 그러나 대화방의 일부인 전체 사용자 개체에 액세스해야한다면 어떻게 될까요? 그것은 매우 이상한 것처럼 보이는 for-loop (2-level 중첩 된 for-loop!)는 모든 단일 chatroom에서 모든 데이터를 얻기 위해 모든 단일 사용자를 가져와야합니다. 더 좋은 방법이 있습니까? – damirstuhec

    관련 문제