Issue
The "in"
operator works when the number of equality is 10 or less. When it is larger than 10, I will partition the array into multiple sub-arrays of length 10 and initialize multiple query requests.
When the length is less than 10, I am simply using q
as the query request and returning return collectionData(q, { idField: 'id' });
. However, when I have q0
, q1
, etc., I don't know how to return them all the same way as if returning q
.
The question is how to return q0
, q1
, ... using the same syntax as just returning q
?
constructor(private firestore: Firestore) {
}
getUserChats() {
const userId = '12345678910';
const userRef = doc(this.firestore, `users/${userId}`);
return docData(userRef).pipe(
switchMap((data) => {
let userChats = data.chats;
let chatsRef = collection(this.firestore, 'chats');
if (userChats.length <= 10) {
//use the query normally as the 'in' operator has a limit of 10
let q = query(chatsRef, where(documentId(), 'in', userChats));
return collectionData(q, { idField: 'id' });
} else {
//breakdown the userChats array into sub-arrays of length 10
//it is hardcoded for proof-of-concept
let q0 = query(chatsRef, where(documentId(), 'in', userChats.slice(0, 10)));
let q1 = query(chatsRef, where(documentId(), 'in', userChats.slice(10, 20)));
//...
//how to combine q0 and q1?
return collectionData(????????????????, { idField: 'id' });
}
})
);
}
Solution
Here is the solution I have come up with:
- Divide the data into segments of size
10
(the last segment might have10
or less) - For each query, use the
in
operator for each segment, which contains at most10
equalities - Each query will be stored in an array of queries
collectionData
is then used for each query in the array, which returns an observable- All the observables will be stored inside an array of observable
- The function
combineLatest
from RxJS is then used with the array of observables and it then returned
getUserChats() {
const userId = 'aabbccdd';
const userRef = doc(this.firestore, `users/${userId}`);
return docData(userRef).pipe(
switchMap((data) => {
if (data && data.chats) {
const userChats = data.chats;
const chatsRef = collection(this.firestore, 'chats');
let queries = [];
if (userChats.length !== 0) {
for (let i = 0; i < userChats.length; i += 10) {
let q: Query<DocumentData> = query(
chatsRef,
where(documentId(), 'in', userChats.slice(i, i + 10))
);
queries.push(q);
}
let observablesData: Observable<DocumentData[]>[] = [];
for (let i = 0; i < queries.length; i++) {
let x = collectionData(queries[i], { idField: 'id' });
observablesData.push(x);
}
return combineLatest(observablesData);
}
}
return [null];
})
);
}
To test the function, ensure to check for the null
case, as this will thrown an exception:
this.chatService
.getUserChats()
.pipe()
.subscribe((result: FirebaseChatroom[]) => {
if (result !== null) {
result = result.flat();
//do something with result...
}
});
Answered By - M. Al Jumaily
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.