Google Firestore - 여러 ID로 여러 문서를 한 번의 왕복으로 가져오는 방법
파이어스토어 데이터베이스로의 왕복(네트워크 통화) 한 번에 ID 목록으로 여러 문서를 받을 수 있는지 궁금합니다.
노드 내에 있는 경우:
https://github.com/googleapis/nodejs-firestore/blob/master/dev/src/index.ts#L978
/**
* Retrieves multiple documents from Firestore.
*
* @param {...DocumentReference} documents - The document references
* to receive.
* @returns {Promise<Array.<DocumentSnapshot>>} A Promise that
* contains an array with the resulting document snapshots.
*
* @example
* let documentRef1 = firestore.doc('col/doc1');
* let documentRef2 = firestore.doc('col/doc2');
*
* firestore.getAll(documentRef1, documentRef2).then(docs => {
* console.log(`First document: ${JSON.stringify(docs[0])}`);
* console.log(`Second document: ${JSON.stringify(docs[1])}`);
* });
*/
이것은 특히 서버 SDK용입니다.
업데이트: 이제 클라우드 Firestore가 IN 쿼리를 지원합니다!
myCollection.where(firestore.FieldPath.documentId(), 'in', ["123","456","789"])
실제로 당신은 파이어스토어를 사용할 것입니다. 이렇게 하십시오.
async getUsers({userIds}) {
const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
const users = await this.firestore.getAll(...refs)
console.log(users.map(doc => doc.data()))
}
또는 약속 구문을 사용합니다.
getUsers({userIds}) {
const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
this.firestore.getAll(...refs).then(users => console.log(users.map(doc => doc.data())))
}
그들은 방금 이 기능인 https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html 을 발표했습니다.
이제 와 같은 쿼리를 사용할 수 있지만 입력 크기는 10보다 클 수 없습니다.
userCollection.where('uid', 'in', ["1231","222","2131"])
Firebase Version 9(2021년 12월 업데이트)
"documentId()" 및 "in" with "where" 절을 사용하여 여러 ID에 의한 여러 문서를 한 번의 왕복으로 가져올 수 있습니다.
import {
query,
collection,
where,
documentId,
getDocs
} from "firebase/firestore";
const q = query(
collection(db, "products"),
where(documentId(), "in",
[
"8AVJvG81kDtb9l6BwfCa",
"XOHS5e3KY9XOSV7YYMw2",
"Y2gkHe86tmR4nC5PTzAx"
]
),
);
const productsDocsSnap = await getDocs(q);
productsDocsSnap.forEach((doc) => {
console.log(doc.data()); // "doc1", "doc2" and "doc3"
});
다음과 같은 기능을 사용할 수 있습니다.
function getById (path, ids) {
return firestore.getAll(
[].concat(ids).map(id => firestore.doc(`${path}/${id}`))
)
}
단일 ID로 호출할 수 있습니다.
getById('collection', 'some_id')
또는 ID 배열:
getById('collection', ['some_id', 'some_other_id'])
아니요, 현재 Cloud Firestore SDK를 사용하여 여러 읽기 요청을 일괄 처리할 수 있는 방법이 없으므로 한 번에 모든 데이터를 읽을 수 있다고 보장할 수 없습니다.
그러나 Frank van Puffelen이 위의 의견에서 말했듯이 이것은 3개의 문서를 가져오는 것이 하나의 문서를 가져오는 것보다 3배 느리다는 것을 의미하지 않습니다.여기서 결론을 내리기 전에 직접 측정을 수행하는 것이 가장 좋습니다.
플래터를 사용하는 경우 다음을 수행할 수 있습니다.
Firestore.instance.collection('your_collection_name')
.where(FieldPath.documentId, whereIn:["list", "of", "document", "ids"])
.getDocuments();
▁a▁future가 포함된 Future를 합니다.List<DocumentSnapshot>
당신이 적합하다고 느끼면서 반복할 수 있습니다.
이를 위한 가장 좋은 방법은 클라우드 기능에서 Firestore의 실제 쿼리를 구현하는 것입니까?그러면 고객으로부터 파이어베이스로의 왕복 전화가 한 번만 올 것이고, 이것이 당신이 요구하는 것처럼 보입니다.
어쨌든 당신은 이 서버 측처럼 모든 데이터 액세스 로직을 유지하고 싶을 것입니다.
내부적으로 Firebase 자체에 대한 호출 수는 동일할 수 있지만, 모두 외부 네트워크가 아닌 Google의 초고속 상호 연결을 통해 이루어질 것이며 Frank van Puffelen이 설명한 파이프라이닝과 결합하면 이 접근 방식에서 우수한 성능을 얻을 수 있습니다.
문서 ID(최대 10개)로 IN 쿼리를 수행할 수 있습니다.
import {
query,
collection,
where,
getDocs,
documentId,
} from 'firebase/firestore';
export async function fetchAccounts(
ids: string[]
) {
// use lodash _.chunk, for example
const result = await Promise.all(
chunk(ids, 10).map(async (chunkIds) => {
const accounts = await getDocs(
query(
collection(firestore, 'accounts'),
where(documentId(), 'in', chunkIds)
));
return accounts.docs.filter(doc => doc.exists()).map(doc => doc.data());
})
);
return result.flat(1);
}
다음은 안드로이드 SDK를 사용하여 코틀린에서 이와 같은 작업을 수행하는 방법입니다.
반드시 한 번의 왕복에 있을 필요는 없지만 효과적으로 결과를 그룹화하고 많은 중첩된 콜백을 방지합니다.
val userIds = listOf("123", "456")
val userTasks = userIds.map { firestore.document("users/${it!!}").get() }
Tasks.whenAllSuccess<DocumentSnapshot>(userTasks).addOnSuccessListener { documentList ->
//Do what you need to with the document list
}
모든 문서를 가져오고 결과를 필터링하는 것보다 특정 문서를 가져오는 것이 훨씬 좋습니다.이는 Firestore가 쿼리 결과 집합에 대해 사용자에게 요금을 부과하기 때문입니다.
동일한 문제에 봉착한 일부 사람들을 위해 다음과 같은 것이 있습니다.
List<String> documentsIds = {your document ids};
FirebaseFirestore.getInstance().collection("collection_name")
.whereIn(FieldPath.documentId(), documentsIds).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : Objects.requireNonNull(task.getResult())) {
YourClass object = document.toObject(YourClass.class);
// add to your custom list
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
}
});
이것이 당신에게 도움이 되기를 바랍니다, 저에게 효과가 있습니다.
getCartGoodsData(id) {
const goodsIDs: string[] = [];
return new Promise((resolve) => {
this.fs.firestore.collection(`users/${id}/cart`).get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
goodsIDs.push(doc.id);
});
const getDocs = goodsIDs.map((id: string) => {
return this.fs.firestore.collection('goods').doc(id).get()
.then((docData) => {
return docData.data();
});
});
Promise.all(getDocs).then((goods: Goods[]) => {
resolve(goods);
});
});
});
}
Angular를 사용하여 이 작업을 수행하려는 사용자를 위한 예는 다음과 같습니다.
먼저 일부 라이브러리 가져오기가 필요합니다(사전 설치해야 함).
import * as firebase from 'firebase/app'
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore'
컬렉션에 대한 일부 구성:
yourCollection: AngularFirestoreCollection;
constructor(
private _db : AngularFirestore,
) {
// this is your firestore collection
this.yourCollection = this._db.collection('collectionName');
}
쿼리를 수행하는 방법은 다음과 같습니다('products_id'는 ID의 배열입니다).
getProducts(products_ids) {
var queryId = firebase.firestore.FieldPath.documentId();
this.yourCollection.ref.where(queryId, 'in', products_ids).get()
.then(({ docs }) => {
console.log(docs.map(doc => doc.data()))
})
}
네, 가능합니다.Firestore용 .NET SDK의 샘플:
/*List of document references, for example:
FirestoreDb.Collection(ROOT_LEVEL_COLLECTION).Document(DOCUMENT_ID);*/
List<DocumentReference> docRefList = YOUR_DOCUMENT_REFERENCE_LIST;
// Required fields of documents, not necessary while fetching entire documents
FieldMask fieldMask = new FieldMask(FIELD-1, FIELD-2, ...);
// With field mask
List<DocumentSnapshot> documentSnapshotsMasked = await FirestoreDb.GetAllSnapshotsAsync(docRefList, fieldMask);
// Without field mask
List<DocumentSnapshot>documentSnapshots = await FirestoreDb.GetAllSnapshotsAsync(docRefList);
.NET의 설명서:
현재 파이어스토어에서는 이것이 불가능할 것 같습니다.알렉산더의 답변이 왜 받아들여지는지 이해할 수 없는데, 그가 제안하는 솔루션은 "사용자" 컬렉션의 모든 문서를 반환합니다.
수행해야 하는 작업에 따라 표시해야 하는 관련 데이터의 복제를 조사하고 필요할 때만 전체 문서를 요청해야 합니다.
python firebase admin skd를 사용하는 경우 uid를 사용하여 여러 문서를 쿼리하는 방법입니다.
from firebase_admin import firestore
import firebase_admin
from google.cloud.firestore_v1.field_path import FieldPath
app = firebase_admin.initialize_app(cred)
client = firestore.client(app)
collection_ref = client.collection('collection_name')
query = collection_ref.where(FieldPath.document_id(), 'in', listOfIds)
docs = query.get()
for doc in docs:
print(doc.id, doc.to_dict())
가져오는 대신FieldPath
당신은 또한 간단하게 문자열을 사용할 수 있습니다.__name__
이제 당신의 질문은collection_ref.where('__name__', 'in', listOfIds)
사용하지 않는 것이 최선입니다.Promise.all
당신의 고객이 기다려야 하는 것처럼..all
진행하기 전의 판독치.
읽기를 반복하고 독립적으로 해결합니다.클라이언트 측에서는 여러 진행률 로더 이미지를 독립적으로 값으로 확인하는 UI로 요약할 수 있습니다.하지만, 이것은 고객 전체를 동결시키는 것보다 낫습니다..all
읽기가 해결됩니다.
따라서 모든 동기화 결과를 즉시 보기에 덤프한 다음 비동기화 결과가 해결될 때 개별적으로 들어오도록 합니다.이것은 사소한 차이처럼 보일 수도 있지만, 만약 당신의 고객이 인터넷 연결이 좋지 않다면(나는 현재 이 커피숍에 있는 것처럼), 전체 고객 경험을 몇 초 동안 동결하는 것은 '이 앱을 망친다'는 결과를 초래할 가능성이 높습니다.
언급URL : https://stackoverflow.com/questions/46721517/google-firestore-how-to-get-several-documents-by-multiple-ids-in-one-round-tri
'source' 카테고리의 다른 글
SQL Server에서 기본 키 열 변경 (0) | 2023.06.20 |
---|---|
Oracle의 열에 시퀀스가 있는지 확인합니다. (0) | 2023.06.15 |
스위치 대/소문자: 오류: 대/소문자 레이블이 정수 상수로 줄어들지 않음 (0) | 2023.06.15 |
ORA-01658: 테이블스페이스 TS_DATA에서 세그먼트에 대한 INITIAL 익스텐트를 생성할 수 없습니다. (0) | 2023.06.15 |
요인 수준과 요인 레이블 간의 혼동 (0) | 2023.06.15 |