Cloud Firestore를 사용하여 컬렉션의 문서 수를 가져오는 방법
Firestore에서 컬렉션의 총 문서 수를 얻으려면 어떻게 해야 합니까?
예를 들어, 만약 내가.
/people
/123456
/name - 'John'
/456789
/name - 'Jane'
저는 제가 몇 명인지 물어보고 2명을 받고 싶습니다.
/people에 대한 쿼리를 수행한 다음 반환된 결과의 길이를 얻을 수 있지만, 특히 대규모 데이터셋에서 이 작업을 수행할 예정이기 때문에 이 작업이 낭비되는 것 같습니다.
현재 세 가지 옵션이 있습니다.
옵션 1: 클라이언트 측
이것은 기본적으로 당신이 언급한 접근법입니다.컬렉션에서 모두를 선택하고 클라이언트 측에서 카운트합니다.이것은 소규모 데이터 세트에 충분히 효과적이지만 데이터 세트가 더 크면 분명히 작동하지 않습니다.
옵션 2: 쓰기 시간 최적화
이 방법을 사용하면 클라우드 기능을 사용하여 컬렉션에서 추가 및 삭제할 때마다 카운터를 업데이트할 수 있습니다.
추가/삭제가 초당 1개 이하의 속도로만 발생하는 한 모든 데이터셋 크기에 적합합니다.이렇게 하면 거의 최신 카운트를 즉시 제공하기 위해 읽을 단일 문서가 제공됩니다.
초당 1개를 초과해야 하는 경우 설명서에 따라 분산 카운터를 구현해야 합니다.
옵션 3: 정확한 쓰기 시간
클라우드 기능을 사용하는 대신 클라이언트에서 문서를 추가하거나 삭제하는 동시에 카운터를 업데이트할 수 있습니다.즉, 카운터도 최신 상태가 되지만 문서를 추가하거나 삭제할 때 이 논리를 포함해야 합니다.
옵션 2와 마찬가지로 초당 초과하려면 분산 카운터를 구현해야 합니다.
집계가 방법입니다(클라이언트 측에서 노출을 원하지 않을 수 있는 정보를 사용자에게 노출하기 때문에 파이어베이스 기능은 이러한 집계를 업데이트하는 권장 방법으로 보입니다). https://firebase.google.com/docs/firestore/solutions/aggregation
큰 목록에 적합하지 않고 전체 목록을 다운로드하는 다른 방법(권장하지 않음): res.size(권장하지 않음)
db.collection("logs")
.get()
.then((res) => console.log(res.size));
하면 (AngulareFire2를 사용한다고 하면) 할 수 .private afs: AngularFirestore
생성자에 주입됨):
this.afs.collection(myCollection).valueChanges().subscribe( values => console.log(values.length));
여기서,values
는 의모항배다니열입에 있는 입니다.myCollection
사용할 수 있도록 메타데이터가 필요하지 않습니다.valueChanges()
직접적인 방법.
클라우드 기능이 있는 대규모 컬렉션의 경우 문서 수를 세는 데 주의해야 합니다.모든 수집에 대해 미리 계산된 카운터를 사용하려면 Firestore 데이터베이스가 약간 복잡합니다.
이 경우에는 다음과 같은 코드가 작동하지 않습니다.
export const customerCounterListener =
functions.firestore.document('customers/{customerId}')
.onWrite((change, context) => {
// on create
if (!change.before.exists && change.after.exists) {
return firestore
.collection('metadatas')
.doc('customers')
.get()
.then(docSnap =>
docSnap.ref.set({
count: docSnap.data().count + 1
}))
// on delete
} else if (change.before.exists && !change.after.exists) {
return firestore
.collection('metadatas')
.doc('customers')
.get()
.then(docSnap =>
docSnap.ref.set({
count: docSnap.data().count - 1
}))
}
return null;
});
그 이유는 파이어스토어 설명서에 나와 있듯이 모든 클라우드 파이어스토어 트리거는 동일해야 하기 때문입니다. https://firebase.google.com/docs/functions/firestore-events#limitations_and_guarantees
해결책
따라서 코드가 여러 번 실행되지 않도록 하려면 이벤트 및 트랜잭션을 관리해야 합니다.다음은 대규모 수집 카운터를 처리하는 특별한 방법입니다.
const executeOnce = (change, context, task) => {
const eventRef = firestore.collection('events').doc(context.eventId);
return firestore.runTransaction(t =>
t
.get(eventRef)
.then(docSnap => (docSnap.exists ? null : task(t)))
.then(() => t.set(eventRef, { processed: true }))
);
};
const documentCounter = collectionName => (change, context) =>
executeOnce(change, context, t => {
// on create
if (!change.before.exists && change.after.exists) {
return t
.get(firestore.collection('metadatas')
.doc(collectionName))
.then(docSnap =>
t.set(docSnap.ref, {
count: ((docSnap.data() && docSnap.data().count) || 0) + 1
}));
// on delete
} else if (change.before.exists && !change.after.exists) {
return t
.get(firestore.collection('metadatas')
.doc(collectionName))
.then(docSnap =>
t.set(docSnap.ref, {
count: docSnap.data().count - 1
}));
}
return null;
});
사용 사례:
/**
* Count documents in articles collection.
*/
exports.articlesCounter = functions.firestore
.document('articles/{id}')
.onWrite(documentCounter('articles'));
/**
* Count documents in customers collection.
*/
exports.customersCounter = functions.firestore
.document('customers/{id}')
.onWrite(documentCounter('customers'));
보시다시피 다중 실행을 방지하는 핵심은 컨텍스트 개체의 eventId라는 속성입니다.동일한 이벤트에 대해 여러 번 기능을 처리한 경우 이벤트 ID는 모든 경우에서 동일합니다.데이터베이스에 "이벤트" 컬렉션이 있어야 합니다.
다른 스레드에서 찾은 아래 답변 확인 부탁드립니다.숫자는 원자여야 합니다.이러한 경우에는 FieldValue.increment() 함수를 사용해야 합니다.
https://stackoverflow.com/a/49407570/3337028
소방 기지 관리자 제공select(fields)
컬렉션 내의 문서에 대한 특정 필드만 가져올 수 있습니다.용사를 합니다.select
모든 필드를 가져오는 것보다 성능이 뛰어납니다.그러나 다음 기간에만 사용할 수 있습니다.firebase-admin
그리고.firebase-admin
일반적으로 서버 측에서만 사용됩니다.
select
다음과 같이 사용할 수 있습니다.
select('age', 'name') // fetch the age and name fields
select() // select no fields, which is perfect if you just want a count
select
Node.js 서버에서 사용할 수 있지만 다른 언어에 대해서는 잘 모르겠습니다.
https://googleapis.dev/nodejs/firestore/latest/Query.html#선택 https://googleapis.dev/nodejs/firestore/latest/CollectionReference.html# 선택
Node.측 함수가 이 함수는 Node..js를 사용합니다.select
필터링된 컬렉션을 카운트하고 모든 결과 문서의 ID를 가져옵니다.TS로 작성되었지만 쉽게 JS로 변환됩니다.
import admin from 'firebase-admin'
// https://stackoverflow.com/questions/46554091/cloud-firestore-collection-count
// we need to use admin SDK here as select() is only available for admin
export const videoIds = async (req: any): Promise<any> => {
const id: string = req.query.id || null
const group: string = req.query.group || null
let processed: boolean = null
if (req.query.processed === 'true') processed = true
if (req.query.processed === 'false') processed = false
let q: admin.firestore.Query<admin.firestore.DocumentData> = admin.firestore().collection('videos')
if (group != null) q = q.where('group', '==', group)
if (processed != null) q = q.where('flowPlayerProcessed', '==', processed)
// select restricts returned fields such as ... select('id', 'name')
const query: admin.firestore.QuerySnapshot<admin.firestore.DocumentData> = await q.orderBy('timeCreated').select().get()
const ids: string[] = query.docs.map((doc: admin.firestore.QueryDocumentSnapshot<admin.firestore.DocumentData>) => doc.id) // ({ id: doc.id, ...doc.data() })
return {
id,
group,
processed,
idx: id == null ? null : ids.indexOf(id),
count: ids.length,
ids
}
}
클라우드 기능 HTTP 요청은 각 문서에 많은 데이터가 포함된 500개의 문서 모음에 대해 1초 이내에 완료됩니다. 정도로 하지 않는 것보다 훨씬 .select
클라이언트 측 캐싱(또는 서버 측 캐싱)을 도입하여 성능을 개선할 수 있습니다.
클라우드 기능 시작 지점은 다음과 같습니다.
exports.videoIds = functions.https.onRequest(async (req, res) => {
const response: any = await videoIds(req)
res.json(response)
})
HTTP 요청 URL은 다음과 같습니다.
https://SERVER/videoIds?group=my-group&processed=true
Firebase 기능은 서버가 배치된 위치를 자세히 설명합니다.
Dan Answer:데이터베이스에 별도의 카운터를 두고 Cloud Functions를 사용하여 유지 관리할 수 있습니다. (쓰기 시간 최선의 노력)
// Example of performing an increment when item is added
module.exports.incrementIncomesCounter = collectionRef.onCreate(event => {
const counterRef = event.data.ref.firestore.doc('counters/incomes')
counterRef.get()
.then(documentSnapshot => {
const currentCount = documentSnapshot.exists ? documentSnapshot.data().count : 0
counterRef.set({
count: Number(currentCount) + 1
})
.then(() => {
console.log('counter has increased!')
})
})
})
이 코드는 방법의 완전한 예를 보여줍니다. https://gist.github.com/saintplay/3f965e0aea933a1129cc2c9a823e74d7
새 쓰기 배치 가져오기
WriteBatch batch = db.batch();
컬렉션 "NYC"에 새 값 추가
DocumentReference nycRef = db.collection("cities").document();
batch.set(nycRef, new City());
ID가 카운트이고 초기 값이 합계=0인 문서 유지 관리
추가 작업 중에는 다음과 같은 작업을 수행합니다.
DocumentReference countRef= db.collection("cities").document("count");
batch.update(countRef, "total", FieldValue.increment(1));
삭제 작업 중에는 다음과 같이 수행합니다.
DocumentReference countRef= db.collection("cities").document("count");
batch.update(countRef, "total", FieldValue.increment(-1));
항상 문서 개수 가져오기
DocumentReference nycRef = db.collection("cities").document("count");
모든 카운터를 처리할 NPM 패키지를 만들었습니다.
먼저 functions 디렉토리에 모듈을 설치합니다.
npm i adv-firestore-functions
그런 다음 다음과 같이 사용합니다.
import { eventExists, colCounter } from 'adv-firestore-functions';
functions.firestore
.document('posts/{docId}')
.onWrite(async (change: any, context: any) => {
// don't run if repeated function
if (await eventExists(context)) {
return null;
}
await colCounter(change, context);
}
이벤트 및 기타 모든 것을 처리합니다.
모든 기능에 대해 범용 카운터로 설정하려는 경우:
import { eventExists, colCounter } from 'adv-firestore-functions';
functions.firestore
.document('{colId}/{docId}')
.onWrite(async (change: any, context: any) => {
const colId = context.params.colId;
// don't run if repeated function
if (await eventExists(context) || colId.startsWith('_')) {
return null;
}
await colCounter(change, context);
}
그리고 당신의 규칙을 잊지 마세요.
match /_counters/{document} {
allow read;
allow write: if false;
}
물론 다음과 같은 방법으로 액세스할 수 있습니다.
const collectionPath = 'path/to/collection';
const colSnap = await db.doc('_counters/' + collectionPath).get();
const count = colSnap.get('count');
자세히 보기: https://code.build/p/9DicAmrnRoK4uk62Hw1bEV/firestore-counters GitHub: https://github.com/jdgamble555/adv-firestore-functions
트랜잭션을 사용하여 데이터베이스 쓰기의 성공 수신기 내 개수를 업데이트합니다.
FirebaseFirestore.getInstance().runTransaction(new Transaction.Function<Long>() {
@Nullable
@Override
public Long apply(@NonNull Transaction transaction) throws FirebaseFirestoreException {
DocumentSnapshot snapshot = transaction
.get(pRefs.postRef(forumHelper.getPost_id()));
long newCount;
if (b) {
newCount = snapshot.getLong(kMap.like_count) + 1;
} else {
newCount = snapshot.getLong(kMap.like_count) - 1;
}
transaction.update(pRefs.postRef(forumHelper.getPost_id()),
kMap.like_count, newCount);
return newCount;
}
});
언급URL : https://stackoverflow.com/questions/46553314/how-to-get-a-count-of-number-of-documents-in-a-collection-with-cloud-firestore
'source' 카테고리의 다른 글
numpy 배열을 튜플로 변환 (0) | 2023.07.16 |
---|---|
Python: print 명령으로 줄 바꿈 방지 (0) | 2023.07.16 |
표의 한 열만 기준으로 중복 값 제거 (0) | 2023.07.16 |
정적 메소드 - 다른 메소드에서 메소드를 호출하는 방법은 무엇입니까? (0) | 2023.07.16 |
Python 웹 프레임워크, WSGI 및 CGI의 적합성 (0) | 2023.07.16 |