Firebase 쿼리 "IN" 제한을 10으로 설정할 수 있는 해결 방법이 있습니까?
크기가 10보다 큰 ID 배열을 가진 파이어베이스에 대한 쿼리가 있습니다.Firebase에는 한 세션에서 쿼리할 레코드 수에 제한이 있습니다.한 번에 10개 이상을 조회할 수 있는 방법이 있습니까?
[처리되지 않은 약속 거부:Firebase 오류:잘못된 쿼리입니다.'in' 필터는 값 배열에서 최대 10개의 요소를 지원합니다.]
https://cloud.google.com/firestore/docs/query-data/queries
let query = config.db
.collection(USER_COLLECTION_NAME)
.where("id", "in", matchesIdArray);
const users = await query.get();
(matchIdArray.length는 무제한이어야 합니다.)
저는 이것이 가능한 한 많은 질문(루프 및 요청을 10개씩 배치)을 하지 않아도 잘 작동한다는 것을 알게 되었습니다.
export async function getContentById(ids, path) {
// don't run if there aren't any ids or a path for the collection
if (!ids || !ids.length || !path) return [];
const collectionPath = db.collection(path);
const batches = [];
while (ids.length) {
// firestore limits batches to 10
const batch = ids.splice(0, 10);
// add the batch request to to a queue
batches.push(
collectionPath
.where(
firebase.firestore.FieldPath.documentId(),
'in',
[...batch]
)
.get()
.then(results => results.docs.map(result => ({ /* id: result.id, */ ...result.data() }) ))
)
}
// after all of the data is fetched, return it
return Promise.all(batches)
.then(content => content.flat());
}
최상의 방법
목록을 각각 10개 항목의 하위 목록이 포함된 목록으로 변환한 다음 두 번째 목록을 통과하고 각 루프의 파이어베이스를 통해 쿼리를 수행합니다.
예:
List<String> phoneNumbers = ['+12313','+2323','1323','32323','32323','3232', '1232']; //CAN BE UPTO 100 or more
전화 번호를 각각 10개 항목의 하위 목록으로 변환
List<List<String>> subList = [];
for (var i = 0; i < phoneNumbers.length; i += 10) {
subList.add(
phoneNumbers.sublist(i, i + 10> phoneNumbers.length ? phoneNumbers.length : i + 10));
}
지금 Firebase 쿼리 실행
subList.forEach((element) {
firestore
.collection('Stories')
.where('userPhone', whereIn: element)
.get()
.then((value) {
value.docs.forEach((snapshot) {
//handle the list
});
});
해결 방법은 일반적으로 단일 "in" 쿼리와 함께 사용하는 어레이의 각 항목에 대해 하나의 쿼리를 만드는 것입니다.또는 배열에서 요청을 배치합니다.
let query = config.db
.collection(USER_COLLECTION_NAME)
.where("id", "==", matchesIdArray[0]);
const users = await query.get();
당신은 위의 코드를 사용해야 할 것입니다.matchesIdArray
모든 결과가 완료된 후 결과를 병합합니다.
이 제한을 해결하는 일반적인 방법 중 하나는 항목을 일괄적으로 검색한 다음 각 쿼리의 결과를 순차적으로 또는 병렬로 처리하는 것입니다.
또 다른 일반적인 해결 방법은 사용자의 개별 요청을 처리하기 위해 수십 개의 문서를 읽을 필요가 없는 방식으로 데이터를 모델링하는 것입니다.이 수를 줄일 수 있는 방법을 설명하기는 어렵지만, 이러한 개별 문서에서 필요한 데이터를 하나의 통합 문서로 복제해야 하는 경우가 많습니다.
이에 대한 예: 뉴스 사이트가 있고 5개 범주별로 최신 10개 기사 헤드라인을 표시해야 하는 경우 다음 작업을 수행할 수 있습니다.
- 각 문서에 대해 하나씩 50개의 개별 읽기를 수행합니다.
- 최신 10개 기사의 제목이 있는 문서를 만든 다음 5개의 문서만 읽으면 됩니다(범주당 1개).
- 5개의 카테고리 모두에 대해 최신 10개의 제목이 있는 문서를 만든 다음 해당 문서를 하나만 읽으면 됩니다.
이 마지막 두 시나리오에서는 데이터베이스에 쓰는 코드를 더 복잡하게 만듭니다. 이제 통합 문서도 작성해야 하기 때문입니다.그러나 그 대신 읽을 데이터가 훨씬 적어 비용이 절감되고 앱의 성능이 향상됩니다.이러한 유형의 트레이드오프는 NoSQL 데이터베이스를 사용할 때 매우 일반적이며, 이는 데이터 쓰기보다 읽기 수가 훨씬 많은 시나리오에서 사용되는 경향이 있습니다.
자세한 데이터 모델링 조언은 다음과 같습니다.
저는 같은 문제에 직면했고 타자기를 사용한 해결책은 다음과 같습니다.
- 완전한 관찰을 위해 나는 rxjs forkJoin을 사용했습니다.
getPagesByIds(ids: string[]): Observable<Page[]> {
ids = [...ids];
if (ids.length) {
let observables: Observable<Page[]>[] = [];
while (ids.length) {
let observable = this.afs.collection<Page>(PAGE, ref => ref.where('id', 'in', ids.splice(0, 10))).get().pipe(map(pages => pages.docs.map(page => page.data())))
observables.push(observable)
}
return combineLatest(observables).pipe(map(pages => pages.flat(1)))
}
return of ([])
}
- 불완전한 관찰 가능한 경우 rxjs combineLatest를 사용했습니다.
getPagesByIds(ids: string[]): Observable<Page[]> {
ids = [...ids];
if (ids.length) {
let observables: Observable<Page[]>[] = [];
while (ids.length) {
let observable = this.afs.collection<Page>(PAGE, ref => ref.where('id', 'in', ids.splice(0, 10))).get().pipe(map(pages => pages.docs.map(page => page.data())))
observables.push(observable)
}
return combineLatest(observables).pipe(map(pages => pages.flat(1)))
}
return of ([])
}
'in' 쿼리와 일치하기 위해 10개 이상의 요소가 필요한 매우 일반적인 시나리오는 관련된 모든 사용자에게 그룹 채팅 대화를 표시하는 경우입니다.따라서 해당 채팅 ID와 일치할 수 있는 10개의 "구성원"으로 제한될 수 있지만, 제한되지 않으므로 논리를 뒤집고 "어레이 포함" 쿼리를 사용하는 것은 어떨까요?
의사 코드: "users"라는 이름의 모든 대화 문서에 배열을 만듭니다.관련된 모든 사용자의 ID를 나열한 후 현재 사용자의 ID와 비교합니다.
db
.collection('chats')
.where('usersInvolved', 'array-contains', myUserID)
.onSnapshot(...)
그러면 해당 그룹 대화의 모든 사용자에 대한 모든 대화 대화가 10명의 사용자로 제한되지 않고 표시됩니다.
Firebase 설명서에 따르면 where 필드에서만 최대 10개의 id를 지원합니다. 10개 이상의 요소를 쿼리하려면 각 문서를 개별적으로 쿼리하거나 어레이를 10개의 id로 분할해야 합니다.
각 항목을 개별적으로 쿼리합니다.아래 코드를 확인하십시오.
let usersPromise = [];
usersIds.map((id) => {
usersPromise.push(firestore.collection("users").doc(id).get());
});
Promise.all(usersPromise).then((docs) => {
const users = docs.map((doc) => doc.data());
// do your operations with users list
});
async getInBatch(query, key, arr) {
const promises = new Array(Math.ceil(arr.length / 10))
.fill('')
.map((_, i) => arr.slice(i * 10, (i + 1) * 10))
.map((i) => query.where(key, 'in', i).get());
const batches = await Promise.all(promises);
const docsData = [];
batches.forEach((snapshot) => {
snapshot.forEach((doc) => {
docsData.push([doc.id, doc.data()]);
});
});
return docsData;
}
const data = await this.getInBatch(db.collection('collection'),
'id',
[1,2,3]
);
Javascript의 경우, 이것은 약속을 사용한 저의 구현이었습니다.모든.
코드의 첫 번째 부분은 배열을 10개의 집합이 있는 절로 그룹화한 다음 Promise.all에서 10개의 각 집합을 실행합니다.결과 배열은 첫 번째 부분에 docid가 있고 두 번째 부분에 docid가 있는 튜플로 반환됩니다.
현재 답변에 완전히 만족하지 못했기 때문에 여기에 저만의 솔루션을 추가합니다.
docsSnap$(queryFn?: QueryFn): Observable<T[]> {
return this.firestore.collection<T>(`${this.basePath}`, queryFn)
.get()
.pipe(map((i: QuerySnapshot<T>) => i.docs
.map((d: QueryDocumentSnapshot<T>) => d.data())));
}
getIdChuncks(allIds: Array<string>): Array<Array<string>> {
const idBatches = [];
while (allIds.length > 0)
idBatches.push(allIds.splice(0, 10));
return idBatches;
}
processBatches(allIds: string[]) {
const batches$ = this.getIdChuncks(allIds)
.map(ids => this
.docsSnap$(ref => ref.where('id', 'in', ids)));
this.items$ = forkJoin(batches$)
.pipe(map(arr => arr.flat()));
}
다음은 10으로 제한된 화재 저장소 쿼리 "IN"(여기서 In/whereNotIn)을 수정하기 위한 Flutter에 대한 Dart Implementation of Conrad Davis 답변입니다.
Future<List<QueryDocumentSnapshot<Map<String, dynamic>>>> getContentById(
{required List<Object?> ids,
required String path,
required String field,
bool whereIn = false}) {
var collectionPath = store.collection(path);
var batches = <Future<List<QueryDocumentSnapshot<Map<String, dynamic>>>>>[];
var batch = ids;
while (ids.length > 0) {
// firestore limits batches to 10
var end = 10;
if (ids.length < 10) end = ids.length;
batch = ids.sublist(0, end);
ids.removeWhere((element) => batch.contains(element));
if (whereIn) {
// add the batch request to to a queue for whereIn
batches.add(collectionPath
.where(field, whereIn: [...batch])
.get()
.then((results) => results.docs));
} else {
// add the batch request to to a queue for whereNotIn
batches.add(collectionPath
.where(field, whereNotIn: [...batch])
.get()
.then((results) => results.docs));
}
}
// after all of the data is fetched, return it
return Future.wait(batches)
.then((content) => content.expand((i) => i).toList());
}
다음과 같이 사용:
getContentById(ids:["John", "Doe", "Mary"], path: "contacts", field: 'name', whereIn:true)
.then((value) async {
for (var doc in value) {
var d = doc.data();
//... Use your data Map<String, dynamic>
}
});
지금 테스트 중인데 in 연산자가 어레이에서 30개 항목을 지원합니다.
const ids = ['1'...'30'] const query = query(collection(db,'posts'))
N개의 쿼리를 만들기 위해 OR을 사용하는 것이 가능합니까?아마도 누군가가 예시를 사용하는 것을 보여줄 수 있습니다.
최근에 한도가 30으로 늘었습니다.분할과 모든 것의 문제는 페이지와 순서에 있습니다.분할을 통해 수행하면 어려운 테이크입니다.
언급URL : https://stackoverflow.com/questions/61354866/is-there-a-workaround-for-the-firebase-query-in-limit-to-10
'programing' 카테고리의 다른 글
Android 플랫폼의 서비스 대 IntentService (0) | 2023.06.05 |
---|---|
R이 지수 표기법(예: e+10)을 사용하지 않도록 강제합니까? (0) | 2023.06.05 |
노드를 제거합니다.Linux 명령줄을 사용하는 JS? (0) | 2023.05.31 |
탐색 스택에서 뷰 컨트롤러 제거 (0) | 2023.05.31 |
SQLAlchemy에서 UUID를 사용하려면 어떻게 해야 합니까? (0) | 2023.05.31 |