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' });
}
})
);
}
Here is the solution I have come up with:
10
(the last segment might have 10
or less)in
operator for each segment, which contains at most 10
equalitiescollectionData
is then used for each query in the array, which returns an observablecombineLatest
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...
}
});