क्या यह गणना करना संभव है कि नए फायरबेस डेटाबेस, क्लाउड फायरस्टार का उपयोग करके किसी संग्रह में कितने आइटम हैं?
अगर ऐसा है, तो मैं वह कैसे करू?
क्या यह गणना करना संभव है कि नए फायरबेस डेटाबेस, क्लाउड फायरस्टार का उपयोग करके किसी संग्रह में कितने आइटम हैं?
अगर ऐसा है, तो मैं वह कैसे करू?
जवाबों:
कई सवालों के साथ, जवाब है - यह निर्भर करता है ।
सामने के छोर पर बड़ी मात्रा में डेटा को संभालते समय आपको बहुत सावधान रहना चाहिए। आपके सामने के छोर को सुस्त महसूस करने के लिए, फायरस्टार आपसे $ 0.60 प्रति मिलियन की दर से आपके द्वारा पढ़े जाने का शुल्क भी लेता है ।
देखभाल के साथ उपयोग करें - फ्रंटेंड उपयोगकर्ता अनुभव हिट हो सकता है
जब तक आप इस लौटे सरणी के साथ बहुत अधिक तर्क नहीं कर रहे हैं तब तक इसे फ्रंट एंड पर संभालना ठीक होना चाहिए।
db.collection('...').get().then(snap => {
size = snap.size // will return the collection size
});
देखभाल के साथ उपयोग करें - फायरस्टार पढ़े गए इनवोकेशन में बहुत अधिक लागत आ सकती है
इसे फ्रंट एंड पर हैंडल करना संभव नहीं है क्योंकि इसमें यूजर्स सिस्टम को धीमा करने की बहुत अधिक क्षमता है। हमें इस लॉजिक सर्वर साइड को हैंडल करना चाहिए और केवल साइज वापस करना चाहिए।
इस पद्धति का दोष यह है कि आप अभी भी फायरस्टार रीड्स (आपके संग्रह के आकार के बराबर) को आमंत्रित कर रहे हैं, जो लंबे समय में आपको उम्मीद से अधिक लागत खत्म कर सकता है।
बादल समारोह:
...
db.collection('...').get().then(snap => {
res.status(200).send({length: snap.size});
});
फ़्रंट एंड:
yourHttpClient.post(yourCloudFunctionUrl).toPromise().then(snap => {
size = snap.length // will return the collection size
})
सबसे स्केलेबल समाधान
FieldValue.increment ()
अप्रैल 2019 के अनुसार फायरस्टार अब काउंटर्स बढ़ाने की अनुमति देता है, पूरी तरह से परमाणु रूप से, और पूर्व डेटा को पढ़े बिना । यह सुनिश्चित करता है कि एक साथ कई स्रोतों से अपडेट करते समय (पहले लेन-देन का उपयोग करके हल किया गया) भी हमारे पास सही काउंटर वैल्यू है, जबकि डेटाबेस रीड्स की संख्या को कम करके हम प्रदर्शन करते हैं।
किसी भी दस्तावेज़ को डिलीट करने या बनाने से हम डेटाबेस में बैठे एक काउंट फ़ील्ड से जोड़ या हटा सकते हैं।
फायरस्टार डॉक्स - डिस्ट्रिब्यूटेड काउंटर्स देखें या डेटा एग्रीगेशन पर एक नजर डालें जेफ डेलानी द्वारा । AngularFire का उपयोग करने वाले किसी के लिए भी उसके मार्गदर्शक वास्तव में शानदार हैं, लेकिन उसके पाठों को अन्य रूपरेखाओं पर भी ले जाना चाहिए।
बादल समारोह:
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;
});
अब दृश्यपटल पर आप संग्रह के आकार को प्राप्त करने के लिए इस नंबरऑफ़डॉक्स फ़ील्ड को क्वेरी कर सकते हैं।
firestore.runTransaction { ... }
ब्लॉक में लिखना चाहिए । यह पहुँच के साथ समसामयिक समस्याओं को हल करता है numberOfDocs
।
ऐसा करने का सबसे सरल तरीका "क्वेरीस्नापशॉट" के आकार को पढ़ना है।
db.collection("cities").get().then(function(querySnapshot) {
console.log(querySnapshot.size);
});
आप "querySnapshot" के अंदर डॉक्स सरणी की लंबाई भी पढ़ सकते हैं।
querySnapshot.docs.length;
या अगर एक "querySnapshot" खाली मान पढ़ने से खाली है, जो एक बूलियन मान लौटाएगा।
querySnapshot.empty;
db.collection.count()
। उन्हें केवल इसके लिए छोड़ने की सोच
जहां तक मुझे पता है कि इसके लिए कोई बिल्ड-इन समाधान नहीं है और यह केवल नोड एसडीके में ही संभव है। अगर आपके पास एक है
db.collection('someCollection')
आप उपयोग कर सकते हैं
.select([fields])
परिभाषित करना कि आप किस क्षेत्र का चयन करना चाहते हैं। यदि आप एक खाली चयन () करते हैं तो आपको दस्तावेज़ संदर्भों की एक सरणी मिलेगी।
उदाहरण:
db.collection('someCollection').select().get().then(
(snapshot) => console.log(snapshot.docs.length)
);
यह समाधान केवल सभी दस्तावेजों को डाउनलोड करने के सबसे खराब स्थिति के लिए एक अनुकूलन है और बड़े संग्रह पर स्केल नहीं करता है!
इस पर भी एक नज़र डालें:
क्लाउड फायरस्टोर के साथ संग्रह में दस्तावेजों की संख्या की गणना कैसे करें
select(['_id'])
तेज हैselect()
बड़े संग्रह के लिए दस्तावेजों की संख्या की सावधानीपूर्वक गणना करें । यह फायरस्टार डेटाबेस के साथ थोड़ा जटिल है यदि आप हर संग्रह के लिए एक पूर्व-निर्धारित काउंटर चाहते हैं।
इस तरह कोड इस मामले में काम नहीं करता है:
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 नामक संपत्ति है । यदि फ़ंक्शन को एक ही इवेंट के लिए कई बार हैंडल किया गया है, तो इवेंट आईडी सभी मामलों में समान होगी। दुर्भाग्य से, आपके डेटाबेस में "ईवेंट" संग्रह होना चाहिए।
context.eventId
हमेशा एक ही ट्रिगर के कई इनवोकेशन पर समान होगा? मेरे परीक्षण में यह सुसंगत प्रतीत होता है, लेकिन मैं इसे बताते हुए कोई "आधिकारिक" दस्तावेज नहीं ढूंढ पा रहा हूं।
2020 में यह अभी भी फायरबेस एसडीके में उपलब्ध नहीं है लेकिन यह फायरबेस एक्सटेंशन (बीटा) में उपलब्ध है हालांकि यह सेटअप और उपयोग के लिए बहुत जटिल है ...
एक उचित दृष्टिकोण
हेल्पर्स ... (क्रिएट / डिलीट बेमानी लगता है लेकिन 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;
}
निर्यात फायरस्टार हुक
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());
});
कार्रवाई में
बिल्डिंग रूट संग्रह और सभी उप संग्रह को ट्रैक किया जाएगा।
यहाँ /counters/
रूट पथ के तहत
अब संग्रह मायने रखता है स्वचालित रूप से और अंततः अद्यतन करेगा! यदि आपको एक गिनती की आवश्यकता है, तो बस संग्रह पथ का उपयोग करें और इसके साथ उपसर्ग करें counters
।
const collectionPath = 'buildings/138faicnjasjoa89/buildingContacts';
const collectionCount = await db
.doc('counters/' + collectionPath)
.get()
.then(snap => snap.get('count'));
मैं @ मैथ्यू के साथ सहमत हूं, अगर आप इस तरह की क्वेरी करते हैं तो बहुत अधिक खर्च होगा ।
[विकासकर्ताओं के लिए सलाहें आगे बढ़ती हैं]
चूंकि हमारे पास इस स्थिति की शुरुआत है, इसलिए हम वास्तव में प्रकार के साथ एक क्षेत्र में सभी काउंटरों को संग्रहीत करने के लिए एक दस्तावेज़ के साथ एक संग्रह अर्थात् काउंटर बना सकते हैं number
।
उदाहरण के लिए:
संग्रह पर प्रत्येक CRUD ऑपरेशन के लिए, काउंटर दस्तावेज़ अपडेट करें:
अगली बार, जब आप संग्रह की संख्या प्राप्त करना चाहते हैं, तो आपको बस दस्तावेज़ फ़ील्ड को क्वेरी / इंगित करना होगा। [1 रीड ऑपरेशन]
इसके अलावा, आप संग्रह नाम को किसी सरणी में संग्रहीत कर सकते हैं, लेकिन यह मुश्किल होगा, फायरबेस में सरणी की स्थिति नीचे दी गई है:
// 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'}
इसलिए, यदि आप संग्रह को हटाने नहीं जा रहे हैं, तो आप वास्तव में हर बार सभी संग्रह को क्वेरी करने के बजाय संग्रह नाम की सूची संग्रहीत करने के लिए सरणी का उपयोग कर सकते हैं।
आशा करता हूँ की ये काम करेगा!
नहीं, अभी एकत्रीकरण प्रश्नों के लिए कोई अंतर्निहित समर्थन नहीं है। हालाँकि कुछ चीजें हैं जो आप कर सकते हैं।
पहले यहाँ पर प्रलेखित है । समग्र जानकारी बनाए रखने के लिए आप लेनदेन या क्लाउड फ़ंक्शंस का उपयोग कर सकते हैं:
यह उदाहरण दिखाता है कि एक सबकोलेक्शन में रेटिंग की संख्या के साथ-साथ औसत रेटिंग का ट्रैक रखने के लिए फ़ंक्शन का उपयोग कैसे करें।
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
});
});
});
});
जेबीबी द्वारा उल्लिखित समाधान भी उपयोगी है यदि आप केवल दस्तावेजों को बार-बार गिनना चाहते हैं। select()
प्रत्येक दस्तावेज़ को डाउनलोड करने से बचने के लिए कथन का उपयोग करना सुनिश्चित करें (यह बहुत अधिक बैंडविड्थ है जब आपको केवल एक गणना की आवश्यकता होती है)। select()
अभी के लिए सर्वर SDK में उपलब्ध है ताकि समाधान एक मोबाइल ऐप में काम न करे।
कोई प्रत्यक्ष विकल्प उपलब्ध नहीं है। आप ऐसा नहीं कर सकते db.collection("CollectionName").count()
। नीचे दो तरीके दिए गए हैं जिनके द्वारा आप एक संग्रह के भीतर दस्तावेजों की संख्या की गिनती पा सकते हैं।
db.collection("CollectionName").get().subscribe(doc=>{
console.log(doc.size)
})
उपरोक्त कोड का उपयोग करके आपका दस्तावेज़ पढ़ता है एक संग्रह के भीतर दस्तावेजों के आकार के बराबर होगा और यही कारण है कि किसी को उपरोक्त समाधान का उपयोग करने से बचना चाहिए।
db.collection("CollectionName").doc("counts")get().subscribe(doc=>{
console.log(doc.count)
})
ऊपर हमने सभी गणना की जानकारी संग्रहीत करने के लिए नाम के साथ एक दस्तावेज बनाया है। आप निम्नलिखित तरीके से गणना दस्तावेज़ को अपडेट कर सकते हैं: -
wrt मूल्य (दस्तावेज़ पढ़ें = 1) और तेजी से डेटा पुनर्प्राप्ति उपरोक्त समाधान अच्छा है।
व्यवस्थापन का उपयोग कर एक काउंटर बढ़ाएँ। 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),
})
);
इस उदाहरण में हम instanceCount
प्रोजेक्ट में हर बार डॉक्यूमेंट को instances
उप संग्रह में शामिल करने के लिए एक क्षेत्र में वृद्धि करते हैं । यदि फ़ील्ड अभी तक मौजूद नहीं है, तो इसे बनाया जाएगा और 1 के लिए बढ़ाया जाएगा।
वृद्धिशील आंतरिक रूप से लेन-देन होता है, लेकिन यदि आपको प्रत्येक 1 सेकंड से अधिक बार वेतन वृद्धि की आवश्यकता है, तो आपको एक वितरित काउंटर का उपयोग करना चाहिए ।
इसे लागू करना बेहतर है onCreate
और onDelete
इसके बजाय onWrite
आप onWrite
अपडेट के लिए कॉल करेंगे जिसका मतलब है कि आप अनावश्यक फ़ंक्शन इनवॉइस पर अधिक पैसा खर्च कर रहे हैं (यदि आप अपने संग्रह में डॉक्स अपडेट करते हैं)।
एक समाधान यह है:
फायरबेस डॉक में एक काउंटर लिखें, जिसे आप एक लेन-देन के भीतर बढ़ाते हैं जब आप एक नई प्रविष्टि बनाते हैं
आप अपनी नई प्रविष्टि (यानी: स्थिति: 4) के क्षेत्र में गिनती को संग्रहीत करते हैं।
फिर आप उस फ़ील्ड (स्थिति DESC) पर एक इंडेक्स बनाते हैं।
आप एक क्वेरी के साथ स्किप + लिमिट कर सकते हैं। कहीं भी ("स्थिति", "<" x) ।ऑडरबाय ("स्थिति", DESC)
उम्मीद है की यह मदद करेगा!
मैंने सभी काउंटर स्थितियों (प्रश्नों को छोड़कर) को संभालने के लिए इन सभी विचारों का उपयोग करके एक सार्वभौमिक फ़ंक्शन बनाया।
एकमात्र अपवाद तब होगा जब ऐसा करने वाले एक सेकंड लिखते हैं, यह आपको धीमा कर देता है। एक उदाहरण एक ट्रेंडिंग पोस्ट पर पसंद किया जाएगा । उदाहरण के लिए, यह एक ब्लॉग पोस्ट पर ओवरकिल है, और आपको अधिक खर्च करेगा। मेरा सुझाव है कि शार्द का उपयोग करते हुए उस मामले में एक अलग फ़ंक्शन बनाएं: https://firebase.google.com/docs/firestore/solutions/colutionsers
// 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);
});;
}
}
यह ईवेंट, वेतन वृद्धि और लेनदेन को संभालता है। इसमें सुंदरता यह है कि यदि आप किसी दस्तावेज़ की सटीकता के बारे में सुनिश्चित नहीं हैं (शायद अभी भी बीटा में हैं), तो आप काउंटर को हटा सकते हैं ताकि यह स्वचालित रूप से उन्हें अगले ट्रिगर पर जोड़ सके। हां, यह लागत, इसलिए इसे अन्यथा नष्ट न करें।
गिनती पाने के लिए इसी तरह की बात:
const collectionPath = 'buildings/138faicnjasjoa89/buildingContacts';
const colSnap = await db.doc('_counters/' + collectionPath).get();
const count = colSnap.get('count');
इसके अलावा, आप डेटाबेस स्टोरेज पर पैसे बचाने के लिए पुरानी घटनाओं को हटाने के लिए क्रोन जॉब (शेड्यूल फंक्शन) बनाना चाहते हैं। आपको कम से कम एक ब्लेज़ प्लान की आवश्यकता है, और कुछ और कॉन्फ़िगरेशन हो सकते हैं। आप इसे प्रत्येक रविवार को रात 11 बजे तक चला सकते हैं, उदाहरण के लिए। https://firebase.google.com/docs/functions/schedule-functions
यह अप्रयुक्त है , लेकिन कुछ ट्वीक के साथ काम करना चाहिए:
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;
});
और आखिरी, firestore.rules में संग्रह की रक्षा करना न भूलें :
match /_counters/{document} {
allow read;
allow write: if false;
}
match /_events/{document} {
allow read, write: if false;
}
अपडेट: प्रश्न
मेरे अन्य उत्तर को जोड़ना यदि आप क्वेरी काउंट को स्वचालित करना चाहते हैं, तो आप अपने क्लाउड फ़ंक्शन में इस संशोधित कोड का उपयोग कर सकते हैं:
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();
जो अपने आप पोस्ट को अपडेट कर देगा यूजरडीन्यूमेंट में। आप आसानी से इस तरह से कई मामलों में अन्य को जोड़ सकते हैं। यह आपको केवल यह बताता है कि आप चीजों को कैसे स्वचालित कर सकते हैं। मैंने आपको ईवेंट हटाने का एक और तरीका भी दिया। आपको इसे हटाने के लिए प्रत्येक तिथि को पढ़ना होगा, इसलिए यह आपको बाद में हटाने के लिए वास्तव में नहीं बचाएगा, बस फ़ंक्शन को धीमा कर देता है।
/**
* 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;
}
मुझे आपको यह भी चेतावनी देनी चाहिए कि सार्वभौमिक कार्य प्रत्येक ऑनराइट कॉल काल पर चलेंगे। यह केवल onCreate पर और अपने विशिष्ट संग्रह के onDelete इंस्टेंस पर फ़ंक्शन चलाने के लिए सस्ता हो सकता है। NoSQL डेटाबेस की तरह हम उपयोग कर रहे हैं, बार-बार कोड और डेटा आपको पैसे बचा सकते हैं।
ऊपर दिए गए कुछ उत्तरों के आधार पर मुझे यह काम करने में थोड़ा समय लगा, इसलिए मैंने सोचा कि मैं इसे दूसरों के उपयोग के लिए साझा करूँगा। मुझे आशा है कि यह उपयोगी है।
'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;
});
मैंने अलग-अलग तरीकों से बहुत कोशिश की है। और अंत में, मैं तरीकों में से एक में सुधार करता हूं। पहले आपको एक अलग संग्रह बनाने और सभी घटनाओं को बचाने की आवश्यकता है। दूसरा आपको समय के अनुसार ट्रिगर होने के लिए एक नया लैम्बडा बनाने की आवश्यकता है। यह मेमना ईवेंट संग्रह और स्पष्ट ईवेंट दस्तावेजों में घटनाओं की गणना करेगा। लेख में कोड विवरण। https://medium.com/@ihor.malaniuk/how-to-count-documents-in-google-cloud-firestore-b0e65863aeca
इस क्वेरी के परिणामस्वरूप दस्तावेज़ की गणना होगी।
this.db.collection(doc).get().subscribe((data) => {
count = data.docs.length;
});
console.log(count)
यह संख्यात्मक यूनिक आईडी बनाने के लिए गिनती का उपयोग करता है। मेरे उपयोग में, मैं कभी भी नहीं घटाऊंगा , तब भी जब document
उस आईडी को हटाने की आवश्यकता हो।
एक ऐसी collection
रचना पर जिसे अद्वितीय संख्यात्मक मान की आवश्यकता होती है
appData
एक दस्तावेज़ के साथ, set
साथ .doc
आईडीonly
uniqueNumericIDAmount
में 0 पर सेट करेंfirebase firestore console
doc.data().uniqueNumericIDAmount + 1
अद्वितीय संख्यात्मक आईडी के रूप में उपयोग करेंappData
संग्रहuniqueNumericIDAmount
firebase.firestore.FieldValue.increment(1)
firebase
.firestore()
.collection("appData")
.doc("only")
.get()
.then(doc => {
var foo = doc.data();
foo.id = doc.id;
// your collection that needs a unique ID
firebase
.firestore()
.collection("uniqueNumericIDs")
.doc(user.uid)// user id in my case
.set({// I use this in login, so this document doesn't
// exist yet, otherwise use update instead of set
phone: this.state.phone,// whatever else you need
uniqueNumericID: foo.uniqueNumericIDAmount + 1
})
.then(() => {
// upon success of new ID, increment uniqueNumericIDAmount
firebase
.firestore()
.collection("appData")
.doc("only")
.update({
uniqueNumericIDAmount: firebase.firestore.FieldValue.increment(
1
)
})
.catch(err => {
console.log(err);
});
})
.catch(err => {
console.log(err);
});
});
firebaseFirestore.collection("...").addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
int Counter = documentSnapshots.size();
}
});