Có thể đếm được bao nhiêu mục mà một bộ sưu tập đã sử dụng cơ sở dữ liệu Firebase mới, Cloud Firestore không?
Nếu vậy, làm thế nào để tôi làm điều đó?
Có thể đếm được bao nhiêu mục mà một bộ sưu tập đã sử dụng cơ sở dữ liệu Firebase mới, Cloud Firestore không?
Nếu vậy, làm thế nào để tôi làm điều đó?
Câu trả lời:
Như với nhiều câu hỏi, câu trả lời là - Nó phụ thuộc .
Bạn nên rất cẩn thận khi xử lý một lượng lớn dữ liệu ở mặt trước. Ngoài việc làm cho mặt trước của bạn cảm thấy chậm chạp, Firestore còn tính phí cho bạn $ 0,60 trên mỗi triệu lượt đọc bạn thực hiện.
Sử dụng cẩn thận - Trải nghiệm người dùng Frontend có thể bị ảnh hưởng
Xử lý điều này ở mặt trước sẽ tốt miễn là bạn không làm quá nhiều logic với mảng trả về này.
db.collection('...').get().then(snap => {
size = snap.size // will return the collection size
});
Sử dụng cẩn thận - Yêu cầu đọc Firestore có thể tốn rất nhiều
Xử lý việc này ở mặt trước là không khả thi vì nó có quá nhiều tiềm năng để làm chậm hệ thống người dùng. Chúng ta nên xử lý phía máy chủ logic này và chỉ trả lại kích thước.
Hạn chế của phương pháp này là bạn vẫn đang thực hiện các lần đọc Firestore (bằng với kích thước của bộ sưu tập của bạn), về lâu dài có thể khiến bạn tốn nhiều tiền hơn dự kiến.
Chức năng đám mây:
...
db.collection('...').get().then(snap => {
res.status(200).send({length: snap.size});
});
Mặt trước:
yourHttpClient.post(yourCloudFunctionUrl).toPromise().then(snap => {
size = snap.length // will return the collection size
})
Giải pháp mở rộng nhất
FieldValue.increment ()
Kể từ tháng 4 năm 2019 Firestore hiện cho phép tăng các bộ đếm, hoàn toàn nguyên tử và không cần đọc dữ liệu trước đó . Điều này đảm bảo chúng tôi có các giá trị truy cập chính xác ngay cả khi cập nhật từ nhiều nguồn đồng thời (đã giải quyết trước đó bằng các giao dịch), đồng thời giảm số lần đọc cơ sở dữ liệu mà chúng tôi thực hiện.
Bằng cách lắng nghe bất kỳ tài liệu nào xóa hoặc tạo, chúng ta có thể thêm hoặc xóa khỏi trường đếm đang ngồi trong cơ sở dữ liệu.
Xem các tài liệu về Firestore - Bộ đếm phân tán Hoặc có cái nhìn về Tập hợp dữ liệu của Jeff Delaney. Hướng dẫn của anh ấy thực sự tuyệt vời cho bất cứ ai sử dụng AngularFire nhưng bài học của anh ấy cũng nên chuyển sang các khuôn khổ khác.
Chức năng đám mây:
export const documentWriteListener =
functions.firestore.document('collection/{documentUid}')
.onWrite((change, context) => {
if (!change.before.exists) {
// New document Created : add one to count
db.doc(docRef).update({numberOfDocs: FieldValue.increment(1)});
} else if (change.before.exists && change.after.exists) {
// Updating existing document : Do nothing
} else if (!change.after.exists) {
// Deleting document : subtract one from count
db.doc(docRef).update({numberOfDocs: FieldValue.increment(-1)});
}
return;
});
Bây giờ trên frontend, bạn chỉ có thể truy vấn trường numberOfDocs này để lấy kích thước của bộ sưu tập.
firestore.runTransaction { ... }
khối. Điều này khắc phục các vấn đề tương tranh với việc truy cập numberOfDocs
.
Cách đơn giản nhất để làm như vậy là đọc kích thước của "querySnapshot".
db.collection("cities").get().then(function(querySnapshot) {
console.log(querySnapshot.size);
});
Bạn cũng có thể đọc độ dài của mảng tài liệu bên trong "querySnapshot".
querySnapshot.docs.length;
Hoặc nếu một "querySnapshot" trống bằng cách đọc giá trị trống, nó sẽ trả về giá trị boolean.
querySnapshot.empty;
db.collection.count()
. Suy nghĩ chỉ thả chúng cho việc này
Theo như tôi biết thì không có giải pháp tích hợp nào cho việc này và nó chỉ có thể có trong nút sdk ngay bây giờ. Nếu bạn có một
db.collection('someCollection')
bạn có thể dùng
.select([fields])
để xác định trường bạn muốn chọn. Nếu bạn chọn select () trống, bạn sẽ chỉ nhận được một mảng các tài liệu tham khảo.
thí dụ:
db.collection('someCollection').select().get().then(
(snapshot) => console.log(snapshot.docs.length)
);
Giải pháp này chỉ là tối ưu hóa cho trường hợp xấu nhất là tải xuống tất cả tài liệu và không mở rộng trên các bộ sưu tập lớn!
Ngoài ra, hãy xem điều này:
Cách lấy số lượng tài liệu trong bộ sưu tập với Cloud Firestore
select(['_id'])
nhanh hơnselect()
Hãy cẩn thận đếm số lượng tài liệu cho các bộ sưu tập lớn . Đó là một chút phức tạp với cơ sở dữ liệu Firestore nếu bạn muốn có một bộ đếm tiền định sẵn cho mỗi bộ sưu tập.
Mã như thế này không hoạt động trong trường hợp này:
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;
});
Lý do là bởi vì mọi kích hoạt Firestore trên đám mây phải là idempotent, như tài liệu về Firestore nói: https://firebase.google.com/docs/fifts/firestore-events#limemony_and_guarantees
Vì vậy, để ngăn chặn nhiều lần thực thi mã của bạn, bạn cần quản lý bằng các sự kiện và giao dịch. Đây là cách đặc biệt của tôi để xử lý các bộ sưu tập lớn:
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;
});
Các trường hợp sử dụng ở đây:
/**
* 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'));
Như bạn có thể thấy, chìa khóa để ngăn chặn nhiều thực thi là thuộc tính được gọi là eventId trong đối tượng bối cảnh. Nếu chức năng đã được xử lý nhiều lần cho cùng một sự kiện, id sự kiện sẽ giống nhau trong mọi trường hợp. Thật không may, bạn phải có bộ sưu tập "sự kiện" trong cơ sở dữ liệu của mình.
context.eventId
sẽ luôn giống nhau trên nhiều lệnh của cùng một trình kích hoạt không? Trong thử nghiệm của tôi, nó có vẻ phù hợp, nhưng tôi không thể tìm thấy bất kỳ tài liệu "chính thức" nào nêu rõ điều này.
Vào năm 2020, điều này vẫn chưa có trong SDK Firebase tuy nhiên nó có sẵn trong Firebase Extension (Beta) tuy nhiên việc cài đặt và sử dụng ... khá phức tạp.
Một cách tiếp cận hợp lý
Người trợ giúp ... (tạo / xóa có vẻ dư thừa nhưng rẻ hơn so với onUpdate)
export const onCreateCounter = () => async (
change,
context
) => {
const collectionPath = change.ref.parent.path;
const statsDoc = db.doc("counters/" + collectionPath);
const countDoc = {};
countDoc["count"] = admin.firestore.FieldValue.increment(1);
await statsDoc.set(countDoc, { merge: true });
};
export const onDeleteCounter = () => async (
change,
context
) => {
const collectionPath = change.ref.parent.path;
const statsDoc = db.doc("counters/" + collectionPath);
const countDoc = {};
countDoc["count"] = admin.firestore.FieldValue.increment(-1);
await statsDoc.set(countDoc, { merge: true });
};
export interface CounterPath {
watch: string;
name: string;
}
Móc Firestore xuất khẩu
export const Counters: CounterPath[] = [
{
name: "count_buildings",
watch: "buildings/{id2}"
},
{
name: "count_buildings_subcollections",
watch: "buildings/{id2}/{id3}/{id4}"
}
];
Counters.forEach(item => {
exports[item.name + '_create'] = functions.firestore
.document(item.watch)
.onCreate(onCreateCounter());
exports[item.name + '_delete'] = functions.firestore
.document(item.watch)
.onDelete(onDeleteCounter());
});
Trong hành động
Bộ sưu tập gốc tòa nhà và tất cả các bộ sưu tập phụ sẽ được theo dõi.
Ở đây dưới /counters/
đường dẫn gốc
Bây giờ số lượng bộ sưu tập sẽ cập nhật tự động và cuối cùng! Nếu bạn cần một số đếm, chỉ cần sử dụng đường dẫn bộ sưu tập và tiền tố với nó counters
.
const collectionPath = 'buildings/138faicnjasjoa89/buildingContacts';
const collectionCount = await db
.doc('counters/' + collectionPath)
.get()
.then(snap => snap.get('count'));
Tôi đồng ý với @Matthew, sẽ tốn rất nhiều chi phí nếu bạn thực hiện truy vấn đó.
[LỜI KHUYÊN CHO CÁC NHÀ PHÁT TRIỂN TRƯỚC KHI BẮT ĐẦU CÁC DỰ ÁN]
Vì chúng tôi đã thấy trước tình huống này ngay từ đầu, nên chúng tôi thực sự có thể tạo ra một bộ sưu tập cụ thể là các bộ đếm với một tài liệu để lưu trữ tất cả các bộ đếm trong một trường có loại number
.
Ví dụ:
Đối với mỗi thao tác CRUD trên bộ sưu tập, hãy cập nhật tài liệu truy cập:
Lần tới, khi bạn muốn lấy số lượng bộ sưu tập, bạn chỉ cần truy vấn / trỏ đến trường tài liệu. [1 thao tác đọc]
Ngoài ra, bạn có thể lưu trữ tên bộ sưu tập trong một mảng, nhưng điều này sẽ rất khó khăn, điều kiện của mảng trong firebase được hiển thị như dưới đây:
// we send this
['a', 'b', 'c', 'd', 'e']
// Firebase stores this
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
// since the keys are numeric and sequential,
// if we query the data, we get this
['a', 'b', 'c', 'd', 'e']
// however, if we then delete a, b, and d,
// they are no longer mostly sequential, so
// we do not get back an array
{2: 'c', 4: 'e'}
Vì vậy, nếu bạn không xóa bộ sưu tập, bạn thực sự có thể sử dụng mảng để lưu danh sách tên bộ sưu tập thay vì truy vấn tất cả bộ sưu tập mỗi lần.
Hy vọng nó giúp!
Không, không có hỗ trợ tích hợp cho các truy vấn tổng hợp ngay bây giờ. Tuy nhiên, có một vài điều bạn có thể làm.
Đầu tiên là tài liệu ở đây . Bạn có thể sử dụng các giao dịch hoặc chức năng đám mây để duy trì thông tin tổng hợp:
Ví dụ này cho thấy cách sử dụng một hàm để theo dõi số lượng xếp hạng trong một bộ sưu tập con, cũng như xếp hạng trung bình.
exports.aggregateRatings = firestore
.document('restaurants/{restId}/ratings/{ratingId}')
.onWrite(event => {
// Get value of the newly added rating
var ratingVal = event.data.get('rating');
// Get a reference to the restaurant
var restRef = db.collection('restaurants').document(event.params.restId);
// Update aggregations in a transaction
return db.transaction(transaction => {
return transaction.get(restRef).then(restDoc => {
// Compute new number of ratings
var newNumRatings = restDoc.data('numRatings') + 1;
// Compute new average rating
var oldRatingTotal = restDoc.data('avgRating') * restDoc.data('numRatings');
var newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;
// Update restaurant info
return transaction.update(restRef, {
avgRating: newAvgRating,
numRatings: newNumRatings
});
});
});
});
Giải pháp mà jbb đề cập cũng hữu ích nếu bạn chỉ muốn đếm tài liệu không thường xuyên. Đảm bảo sử dụng select()
câu lệnh để tránh tải xuống tất cả từng tài liệu (đó là rất nhiều băng thông khi bạn chỉ cần đếm). select()
hiện chỉ có sẵn trong SDK máy chủ để giải pháp không hoạt động trong ứng dụng di động.
Không có tùy chọn trực tiếp có sẵn. Bạn không thể làm được db.collection("CollectionName").count()
. Dưới đây là hai cách mà bạn có thể tìm thấy số lượng tài liệu trong một bộ sưu tập.
db.collection("CollectionName").get().subscribe(doc=>{
console.log(doc.size)
})
Bằng cách sử dụng mã ở trên, tài liệu của bạn đọc sẽ bằng với kích thước của tài liệu trong bộ sưu tập và đó là lý do tại sao người ta phải tránh sử dụng giải pháp trên.
db.collection("CollectionName").doc("counts")get().subscribe(doc=>{
console.log(doc.count)
})
Ở trên, chúng tôi đã tạo một tài liệu với số lượng tên để lưu trữ tất cả thông tin đếm. Bạn có thể cập nhật tài liệu đếm theo cách sau: -
giá wrt (Tài liệu đã đọc = 1) và truy xuất dữ liệu nhanh, giải pháp trên là tốt.
Tăng một bộ đếm bằng admin.firestore.FieldValue.increment :
exports.onInstanceCreate = functions.firestore.document('projects/{projectId}/instances/{instanceId}')
.onCreate((snap, context) =>
db.collection('projects').doc(context.params.projectId).update({
instanceCount: admin.firestore.FieldValue.increment(1),
})
);
exports.onInstanceDelete = functions.firestore.document('projects/{projectId}/instances/{instanceId}')
.onDelete((snap, context) =>
db.collection('projects').doc(context.params.projectId).update({
instanceCount: admin.firestore.FieldValue.increment(-1),
})
);
Trong ví dụ này, chúng tôi tăng một instanceCount
trường trong dự án mỗi khi một tài liệu được thêm vào instances
bộ sưu tập phụ. Nếu trường không tồn tại, nó sẽ được tạo và tăng lên 1.
Gia số là giao dịch nội bộ nhưng bạn nên sử dụng bộ đếm phân tán nếu bạn cần tăng thường xuyên hơn mỗi 1 giây.
Bạn thường nên thực hiện onCreate
và onDelete
thay onWrite
vì bạn sẽ gọi onWrite
cho các bản cập nhật, điều đó có nghĩa là bạn đang chi nhiều tiền hơn cho các yêu cầu chức năng không cần thiết (nếu bạn cập nhật các tài liệu trong bộ sưu tập của mình).
Một cách giải quyết là:
viết một bộ đếm trong tài liệu firebase, mà bạn tăng trong một giao dịch mỗi khi bạn tạo một mục mới
Bạn lưu trữ số đếm trong một trường của mục nhập mới của bạn (ví dụ: vị trí: 4).
Sau đó, bạn tạo một chỉ mục trên trường đó (vị trí DESC).
Bạn có thể thực hiện bỏ qua + giới hạn với một truy vấn. Trường hợp ("vị trí", "<" x) .OrderBy ("vị trí", DESC)
Hi vọng điêu nay co ich!
Tôi đã tạo ra một hàm phổ quát sử dụng tất cả các ý tưởng này để xử lý tất cả các tình huống truy cập (ngoại trừ truy vấn).
Ngoại lệ duy nhất là khi nhiều người viết một giây, nó làm bạn chậm lại. Một ví dụ sẽ là lượt thích trên một bài viết theo xu hướng. Nó là quá mức cần thiết trên một bài đăng blog, ví dụ, và sẽ chi phí bạn nhiều hơn. Tôi đề nghị tạo một chức năng riêng trong trường hợp đó bằng cách sử dụng phân đoạn: https://firebase.google.com/docs/firestore/solutions/counters
// trigger collections
exports.myFunction = functions.firestore
.document('{colId}/{docId}')
.onWrite(async (change: any, context: any) => {
return runCounter(change, context);
});
// trigger sub-collections
exports.mySubFunction = functions.firestore
.document('{colId}/{docId}/{subColId}/{subDocId}')
.onWrite(async (change: any, context: any) => {
return runCounter(change, context);
});
// add change the count
const runCounter = async function (change: any, context: any) {
const col = context.params.colId;
const eventsDoc = '_events';
const countersDoc = '_counters';
// ignore helper collections
if (col.startsWith('_')) {
return null;
}
// simplify event types
const createDoc = change.after.exists && !change.before.exists;
const updateDoc = change.before.exists && change.after.exists;
if (updateDoc) {
return null;
}
// check for sub collection
const isSubCol = context.params.subDocId;
const parentDoc = `${countersDoc}/${context.params.colId}`;
const countDoc = isSubCol
? `${parentDoc}/${context.params.docId}/${context.params.subColId}`
: `${parentDoc}`;
// collection references
const countRef = db.doc(countDoc);
const countSnap = await countRef.get();
// increment size if doc exists
if (countSnap.exists) {
// createDoc or deleteDoc
const n = createDoc ? 1 : -1;
const i = admin.firestore.FieldValue.increment(n);
// create event for accurate increment
const eventRef = db.doc(`${eventsDoc}/${context.eventId}`);
return db.runTransaction(async (t: any): Promise<any> => {
const eventSnap = await t.get(eventRef);
// do nothing if event exists
if (eventSnap.exists) {
return null;
}
// add event and update size
await t.update(countRef, { count: i });
return t.set(eventRef, {
completed: admin.firestore.FieldValue.serverTimestamp()
});
}).catch((e: any) => {
console.log(e);
});
// otherwise count all docs in the collection and add size
} else {
const colRef = db.collection(change.after.ref.parent.path);
return db.runTransaction(async (t: any): Promise<any> => {
// update size
const colSnap = await t.get(colRef);
return t.set(countRef, { count: colSnap.size });
}).catch((e: any) => {
console.log(e);
});;
}
}
Điều này xử lý các sự kiện, gia tăng và giao dịch. Cái hay ở đây là, nếu bạn không chắc về độ chính xác của tài liệu (có thể trong khi vẫn ở bản beta), bạn có thể xóa bộ đếm để nó tự động thêm chúng vào trình kích hoạt tiếp theo. Có, chi phí này, vì vậy đừng xóa nó đi.
Cùng một loại điều để có được số đếm:
const collectionPath = 'buildings/138faicnjasjoa89/buildingContacts';
const colSnap = await db.doc('_counters/' + collectionPath).get();
const count = colSnap.get('count');
Ngoài ra, bạn có thể muốn tạo một công việc định kỳ (chức năng theo lịch trình) để xóa các sự kiện cũ để tiết kiệm tiền cho việc lưu trữ cơ sở dữ liệu. Bạn cần ít nhất một kế hoạch rực sáng, và có thể có thêm một số cấu hình. Bạn có thể chạy nó vào mỗi chủ nhật lúc 11 giờ tối. https://firebase.google.com/docs/fifts/schedule-fifts
Điều này chưa được kiểm tra , nhưng nên hoạt động với một vài điều chỉnh:
exports.scheduledFunctionCrontab = functions.pubsub.schedule('5 11 * * *')
.timeZone('America/New_York')
.onRun(async (context) => {
// get yesterday
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const eventFilter = db.collection('_events').where('completed', '<=', yesterday);
const eventFilterSnap = await eventFilter.get();
eventFilterSnap.forEach(async (doc: any) => {
await doc.ref.delete();
});
return null;
});
Và cuối cùng, đừng quên bảo vệ các bộ sưu tập trong Firestore.rules :
match /_counters/{document} {
allow read;
allow write: if false;
}
match /_events/{document} {
allow read, write: if false;
}
Cập nhật: Truy vấn
Thêm vào câu trả lời khác của tôi nếu bạn cũng muốn tự động hóa số lượng truy vấn, bạn có thể sử dụng mã được sửa đổi này trong chức năng đám mây của mình:
if (col === 'posts') {
// counter reference - user doc ref
const userRef = after ? after.userDoc : before.userDoc;
// query reference
const postsQuery = db.collection('posts').where('userDoc', "==", userRef);
// add the count - postsCount on userDoc
await addCount(change, context, postsQuery, userRef, 'postsCount');
}
return delEvents();
Nó sẽ tự động cập nhật bài viếtCount trong userDocument. Bạn có thể dễ dàng thêm một số khác vào nhiều số theo cách này. Điều này chỉ cung cấp cho bạn ý tưởng về cách bạn có thể tự động hóa mọi thứ. Tôi cũng cho bạn một cách khác để xóa các sự kiện. Bạn phải đọc mỗi ngày để xóa nó, vì vậy nó sẽ không thực sự giúp bạn xóa chúng sau này, chỉ làm cho chức năng chậm hơn.
/**
* Adds a counter to a doc
* @param change - change ref
* @param context - context ref
* @param queryRef - the query ref to count
* @param countRef - the counter document ref
* @param countName - the name of the counter on the counter document
*/
const addCount = async function (change: any, context: any,
queryRef: any, countRef: any, countName: string) {
// events collection
const eventsDoc = '_events';
// simplify event type
const createDoc = change.after.exists && !change.before.exists;
// doc references
const countSnap = await countRef.get();
// increment size if field exists
if (countSnap.get(countName)) {
// createDoc or deleteDoc
const n = createDoc ? 1 : -1;
const i = admin.firestore.FieldValue.increment(n);
// create event for accurate increment
const eventRef = db.doc(`${eventsDoc}/${context.eventId}`);
return db.runTransaction(async (t: any): Promise<any> => {
const eventSnap = await t.get(eventRef);
// do nothing if event exists
if (eventSnap.exists) {
return null;
}
// add event and update size
await t.set(countRef, { [countName]: i }, { merge: true });
return t.set(eventRef, {
completed: admin.firestore.FieldValue.serverTimestamp()
});
}).catch((e: any) => {
console.log(e);
});
// otherwise count all docs in the collection and add size
} else {
return db.runTransaction(async (t: any): Promise<any> => {
// update size
const colSnap = await t.get(queryRef);
return t.set(countRef, { [countName]: colSnap.size }, { merge: true });
}).catch((e: any) => {
console.log(e);
});;
}
}
/**
* Deletes events over a day old
*/
const delEvents = async function () {
// get yesterday
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const eventFilter = db.collection('_events').where('completed', '<=', yesterday);
const eventFilterSnap = await eventFilter.get();
eventFilterSnap.forEach(async (doc: any) => {
await doc.ref.delete();
});
return null;
}
Tôi cũng nên cảnh báo bạn rằng các chức năng phổ quát sẽ chạy trên mọi khoảng thời gian cuộc gọi onWrite. Có thể rẻ hơn khi chỉ chạy chức năng trên onCreate và trên các phiên bản onDelete của các bộ sưu tập cụ thể của bạn. Giống như cơ sở dữ liệu noQuery mà chúng tôi đang sử dụng, mã và dữ liệu lặp lại có thể giúp bạn tiết kiệm tiền.
Mất một thời gian để tôi làm việc này dựa trên một số câu trả lời ở trên, vì vậy tôi nghĩ tôi sẽ chia sẻ nó cho người khác sử dụng. Tôi hy vọng nó hữu ích.
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.countDocumentsChange = functions.firestore.document('library/{categoryId}/documents/{documentId}').onWrite((change, context) => {
const categoryId = context.params.categoryId;
const categoryRef = db.collection('library').doc(categoryId)
let FieldValue = require('firebase-admin').firestore.FieldValue;
if (!change.before.exists) {
// new document created : add one to count
categoryRef.update({numberOfDocs: FieldValue.increment(1)});
console.log("%s numberOfDocs incremented by 1", categoryId);
} else if (change.before.exists && change.after.exists) {
// updating existing document : Do nothing
} else if (!change.after.exists) {
// deleting document : subtract one from count
categoryRef.update({numberOfDocs: FieldValue.increment(-1)});
console.log("%s numberOfDocs decremented by 1", categoryId);
}
return 0;
});
Tôi đã thử rất nhiều với các cách tiếp cận khác nhau. Và cuối cùng, tôi cải thiện một trong những phương pháp. Trước tiên, bạn cần tạo một bộ sưu tập riêng biệt và lưu tất cả các sự kiện. Thứ hai, bạn cần tạo một lambda mới để được kích hoạt theo thời gian. Lambda này sẽ đếm các sự kiện trong bộ sưu tập sự kiện và các tài liệu sự kiện rõ ràng. Mã chi tiết trong bài viết. https://medium.com/@ihor.malaniuk/how-to-count-document-in-google-cloud-firestore-b0e65863aeca
Truy vấn này sẽ dẫn đến số lượng tài liệu.
this.db.collection(doc).get().subscribe((data) => {
count = data.docs.length;
});
console.log(count)
firebaseFirestore.collection("...").addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
int Counter = documentSnapshots.size();
}
});