0

Firebase의 제한 사항입니까? 아니면이 모든 것을 잘못 했습니까? 코드 중간에 db.collection('users').doc(friendId).get()...을 추가 할 때까지 모든 작업이 수행됩니다. 미리 감사드립니다.하위 컬렉션이있는 Firestore 쿼리

const db = admin.firestore(); 
const friendRef = db.collection('users').doc(id).collection('friends'); 

friendsList = []; 

friendRef.get().then((onSnapshot) => { 
    if (!onSnapshot.empty) { 
     onSnapshot.forEach((friend) => { 

      const friendId = String(friend.data().person_id); 

      db.collection('users').doc(friendId).get().then((result) => { 
       const firstName = String(result.data().name.first); 
       const lastName = String(result.data().name.last); 
      }) 

      const data = { 
       personId: friendId, 
       firstName: firstName, 
       lastName: lastName, 
      } 

      friendsList.push(data); 
     }) 

     res.send(friendsList); 
    } else { 
     res.send({ 
      'message': 'no friends' 
     }); 
    } 
}).catch((e) => { 
    res.send({ 
     'error': e 
    }); 
}) 

답변

1

데이터가 Firestore에서 비동기 적으로로드됩니다. 즉, 응답을 클라이언트에 다시 보낼 때까지는 데이터가 아직 Firestore에서로드되지 않았습니다. 그냥이 코드를 실행

console.log("Before getting friend"); 
db.collection('users').doc(friendId).get().then((result) => { 
    console.log("Got friend"); 
}) 
console.log("After getting friend"); 

그것을 인쇄 할 수 있습니다 :

후 친구

을 얻기 전에

이 볼 수있는 가장 쉬운 방법은 몇 가지 절묘한 로깅 문 함께 친구를 사귀는 것

친구를 얻었다

아마도 로그가 예상 된 순서가 아닙니다. 그 이유는 데이터가 Firestore에서 돌아 오는 데 시간이 걸릴 수 있기 때문입니다. 따라서 스레드를 차단하는 대신 스레드를 계속 실행 한 다음 데이터를 사용할 수있을 때 콜백 함수를 호출합니다. 그리고 불행하게도 데이터가 아직로드되지 않았기 때문에 res.send(friendsList)이 빈 목록을 클라이언트에 다시 보내 버리는 것을 의미합니다.

이 솔루션은 Promise.all() 또는 ES6의 새로운 async/await 키워드를 사용하기 위해 여러 콜백 내포 된 콜백을 사용하는 것입니다. 약속의 코드는 다음과 같습니다

const db = admin.firestore(); 
const friendRef = db.collection('users').doc(id).collection('friends'); 

friendRef.get().then((onSnapshot) => { 
    var promises = []; 

    onSnapshot.forEach((friend) => { 
    const friendId = String(friend.data().person_id);  
    promises.push(db.collection('users').doc(friendId).get()); 
    }); 

    Promise.all(promises).then((snapshots) => { 
    friendsList = []; 
    snapshots.forEach((result) => { 
     friendsList.push({ 
     personId: result.id, 
     firstName: result.data().name.first, 
     lastName: result.data().name.last, 
     }); 
    }); 
    res.send(friendsList); 
    }); 
}).catch((e) => { 
    res.send({ 
    'error': e 
    }); 
}) 

그래서 우리는 먼저 우리가 응답을 구축하고 다시 보내, 다음 번에 모든 사람들의이 완료, 읽기 작업을 모든 친구의 목록을 구축 할 수 있습니다.

+0

굉장, 효과가있었습니다. 나는 너의 설명으로 지금 이해한다. 다시 한번 감사드립니다. 나는 이것을 위해 ES6을 사용하고 싶다. 시간이 있고 상관 없으면 ES6 비동기/대기를 사용하여 보낼 수 있습니까? 나는 Google 기능으로 ES6을 배우기 시작할 것입니다. 미리 감사드립니다. –

+0

안녕하세요. 내가 어떤 이유로 든'personId : snapshot.id'에 대한 결과를 얻지 못하는 것을 제외하고는 모두 작동합니다. 나는 snapshot.id와 result.id를 시도했지만 그 중 하나는 작동하지 않았다. 이 코드는'onSnapshot.forEach ((friend) ...'의 ID이며'friend.id'이어야합니다. 다시 한번 감사드립니다. –

+0

코드는'friendId'를 어떻게 초기화했는지 보여주지 않았으므로 문서 ID라고 가정했습니다. : https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentSnapshot#~id. 그렇지 않은 경우 필요에 맞게 솔루션의 해당 부분을 수정해야합니다. –