ক্লাউড ফায়ারস্টোর সংগ্রহের গণনা


149

নতুন ফায়ারবেস ডাটাবেস, ক্লাউড ফায়ার স্টোর ব্যবহার করে কোনও সংগ্রহ কতটি আইটেম ব্যবহার করেছে তা গণনা করা সম্ভব?

যদি তা হয় তবে আমি কীভাবে করব?


উত্তর:


190

আপডেট (এপ্রিল 2019) - FieldValue.increment (বড় সংগ্রহ সমাধান দেখুন)


অনেক প্রশ্নের মতোই উত্তরটি - এটি নির্ভর করে

সামনের প্রান্তে প্রচুর পরিমাণে ডেটা হ্যান্ডেল করার সময় আপনার খুব সতর্ক হওয়া উচিত। আপনার সামনের প্রান্তটি স্বাচ্ছন্দ্য বোধ করার শীর্ষে, ফায়ারস্টোর আপনার তৈরি করা পড়ার জন্য আপনাকে প্রতি মিলিয়ন। 0.60 লাগিয়ে দেয় ।


ছোট সংগ্রহ (100 টিরও কম দস্তাবেজ)

যত্ন সহ ব্যবহার করুন - সম্মুখভাগ ব্যবহারকারীর অভিজ্ঞতা হিট নিতে পারে

সামনের প্রান্তে এটিকে হ্যান্ডেল করা যতক্ষণ না আপনি ফিরে আসা অ্যারের সাথে খুব বেশি যুক্তি না দেখিয়ে ঠিক হওয়া উচিত।

db.collection('...').get().then(snap => {
   size = snap.size // will return the collection size
});

মাঝারি সংগ্রহ (100 থেকে 1000 নথি)

যত্ন সহ ব্যবহার করুন - ফায়ার স্টোর পড়ার অনুরোধগুলির জন্য অনেক বেশি খরচ হতে পারে

সামনের প্রান্তে এটি হ্যান্ডেল করা সম্ভব নয় কারণ এটি ব্যবহারকারী সিস্টেমকে ধীর করে দেওয়ার খুব বেশি সম্ভাবনা রয়েছে। আমাদের এই লজিক সার্ভারটি পরিচালনা করতে হবে এবং কেবল আকারটি ফিরিয়ে আনতে হবে।

এই পদ্ধতির অপূর্ণতা হ'ল আপনি এখনও ফায়ার স্টোর পঠনগুলি (আপনার সংগ্রহের আকারের সমান) অনুরোধ করছেন যা দীর্ঘকালীন সময়ে আপনার প্রত্যাশার চেয়ে বেশি ব্যয় করতে পারে।

মেঘ ফাংশন:

...
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
})

বড় সংগ্রহ (1000+ নথি)

সর্বাধিক স্কেলেবল সমাধান


FieldValue.increment ()

এপ্রিল 2019 হিসাবে ফায়ার স্টোর এখন সম্পূর্ণ পরমাণুভাবে এবং ডেটা পূর্বে পড়া না করে বাড়ানো কাউন্টারের অনুমতি দেয়একসাথে একাধিক উত্স থেকে আপডেট করার সময় (পূর্বে লেনদেনের সাহায্যে সমাধান করা হয়েছে) এমনকি আমাদের কার্যকর ডাটাবেসের পাঠ্য সংখ্যা হ্রাস করার পরেও আমাদের সঠিক পাল্টা মানগুলি নিশ্চিত করে।


মুছে ফেলা বা তৈরি করা কোনও নথির কথা শুনে আমরা ডেটাবেজে বসে থাকা একটি গণনা ক্ষেত্রটি যুক্ত করতে বা সরাতে পারি।

ফায়ার স্টোর ডকগুলি দেখুন - বিতরণ কাউন্টারগুলি বা জেফ ডেলানির ডেটা অগ্রিগেশনটি দেখুন । অ্যাঙ্গুলার ফায়ার ব্যবহার করা তার পক্ষে তার গাইডগুলি সত্যই দুর্দান্ত but তবে তার পাঠগুলি অন্য ফ্রেমওয়ার্কগুলিতেও বহন করা উচিত।

মেঘ ফাংশন:

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;
});

এখন আপনি ফ্রন্টএন্ডে সংগ্রহের আকারটি পেতে এই নম্বরঅফডকস ফিল্ডটিতে কোয়েরি করতে পারেন।


17
বড় সংগ্রহের জন্য দুর্দান্ত সমাধান! আমি কেবল যুক্ত করতে চাই যে প্রয়োগকারীরা একটি firestore.runTransaction { ... }ব্লকে পঠন এবং লিখতে হবে । এটি অ্যাক্সেস সহ সম্মতি সংক্রান্ত সমস্যাগুলি সমাধান করে numberOfDocs
এফিমুনি

2
এই পদ্ধতিগুলি রেকর্ডের সংখ্যার একটি গণনা ব্যবহার করছে। আপনি যদি কোনও লেনদেন ব্যবহার করে কাউন্টার এবং ইনক্রিমেন্ট বাড়ান, তবে কি ক্লাউড ফাংশনের অতিরিক্ত খরচ এবং প্রয়োজন ছাড়াই একই ফলাফল অর্জন করা যাবে না?
ব্যবহারকারী3836415

10
বড় সংগ্রহের সমাধান আদর্শবান নয় এবং কোনও স্কেলে কাজ করে না। ফায়ার স্টোর ডকুমেন্ট ট্রিগারগুলি কমপক্ষে একবার চালানোর গ্যারান্টিযুক্ত তবে এটি একাধিকবার চালাতে পারে। এটি যখন ঘটে, এমনকি কোনও লেনদেনের অভ্যন্তরে আপডেট বজায় রাখাও একাধিকবার চলতে পারে, যা আপনাকে একটি ভুয়া নম্বর দেবে। আমি যখন এটি চেষ্টা করেছি, আমি একবারে কয়েক ডজনেরও বেশি নথি তৈরি নিয়ে ইস্যুগুলিতে ছড়িয়ে পড়েছি।
টিম পোল্যাক

2
হাই @ টিমপল্যাক। ক্লাউড ট্রিগারগুলি ব্যবহার করে আমি কিছু বেমানান আচরণ লক্ষ্য করেছি। আপনি যে অভিজ্ঞতাটি ব্যবহার করেছেন সে সম্পর্কে ব্যাখ্যা করার জন্য আপনি যে কোনও সুযোগে আমাকে এবং নিবন্ধ বা ফোরামে লিঙ্ক করতে পারবেন?
ম্যাথু মুলিন

2
@ ক্যাম্পগ্রাম আপনি db.collection ('...') ব্যবহার করার সময় পুরো সংগ্রহ এবং ডেটা পড়ছেন ... সুতরাং যখন আপনার যখন ডেটার প্রয়োজন হবে না তখন আপনি ঠিক বলেছেন - আপনি সহজেই একটি তালিকার জন্য অনুরোধ করতে পারেন সংগ্রহের আইডি (দস্তাবেজগুলির ডেটা সংগ্রহ নয়) এবং এটি একটি পঠিত হিসাবে গণনা করা হয়।
আটারেশকভ

24

এটি করার সহজ উপায় হ'ল "ক্যোয়ারীস্ন্যাপশট" এর আকার পড়া।

db.collection("cities").get().then(function(querySnapshot) {      
    console.log(querySnapshot.size); 
});

আপনি "ক্যোয়ারীস্ন্যাপশট" এর মধ্যেও ডক্স অ্যারের দৈর্ঘ্যটি পড়তে পারেন।

querySnapshot.docs.length;

অথবা যদি কোনও "ক্যোয়ারীস্ন্যাপশট" খালি মানটি পড়ে খালি হয়, যা একটি বুলিয়ান মান প্রদান করবে।

querySnapshot.empty;

73
প্রতিটি ডকুমেন্ট একটি "পড়তে" পড়তে সচেতন হন। সুতরাং আপনি যদি সংগ্রহে এইভাবে 100 টি আইটেম গণনা করেন তবে আপনার জন্য 100 টি পড়ার জন্য চার্জ নেওয়া হচ্ছে!
জর্জি

সঠিক, তবে সংগ্রহের নথির সংখ্যা যোগ করার জন্য অন্য কোনও উপায় নেই। এবং যদি আপনি ইতিমধ্যে সংগ্রহটি সংগ্রহ করেছেন, "ডক্স" অ্যারে পড়ার জন্য আর কোনও আনার দরকার পড়বে না, সুতরাং আরও পড়ার জন্য "ব্যয়" লাগবে না।
ওপেল

5
এটি স্মরণে সমস্ত নথি পড়ে! বড় ডেটাসেটের জন্য
এটির

85
এটি সত্যই অবিশ্বাস্য যে ফায়ারবেস ফায়ারস্টোরের ধরণের ধরণ নেই db.collection.count()। কেবল এগুলির জন্য তাদের বাদ দেওয়ার কথা ভাবছেন
ব্লু বট

8
বিশেষত বড় সংগ্রহগুলির জন্য, আমাদের চার্জ করা মোটেও ন্যায়সঙ্গত নয় যেন আমরা প্রকৃতভাবে সমস্ত নথি ডাউনলোড করেছি এবং ব্যবহার করেছি। একটি টেবিলের জন্য গণনা (সংগ্রহ) যেমন একটি প্রাথমিক বৈশিষ্ট্য। তাদের মূল্যের মডেলটি বিবেচনা করে এবং ফায়ারস্টোরটি 2017 সালে চালু হয়েছিল, এটি কেবল অবিশ্বাস্য যে গুগল কোনও সংগ্রহের আকার পাওয়ার জন্য কোনও বিকল্প উপায় সরবরাহ করে না। যতক্ষণ না তারা এটি প্রয়োগ করে না, ততক্ষণে তাদের পক্ষে চার্জ করা এড়ানো উচিত।
নিব্বানা

23

যতদূর আমি জানি এটির জন্য কোনও বিল্ট-ইন সমাধান নেই এবং এটি এখনই নোড এসডকেই সম্ভব। যদি তোমার কাছে থাকে একটা

db.collection('someCollection')

তুমি ব্যবহার করতে পার

.select([fields])

আপনি কোন ক্ষেত্রটি নির্বাচন করতে চান তা নির্ধারণ করতে। আপনি যদি খালি নির্বাচন () করেন তবে আপনি কেবলমাত্র নথির রেফারেন্সের একটি অ্যারে পাবেন।

উদাহরণ:

db.collection('someCollection').select().get().then( (snapshot) => console.log(snapshot.docs.length) );

এই দ্রষ্টব্যটি সমস্ত দস্তাবেজগুলি ডাউনলোড করার জন্য সবচেয়ে খারাপ ক্ষেত্রে কেবলমাত্র একটি অপ্টিমাইজেশন এবং বড় সংগ্রহগুলিতে স্কেল করে না!

এছাড়াও এটি দেখুন:
ক্লাউড ফায়ার স্টোর সহ কোনও সংকলনে কীভাবে নথি সংখ্যা গণনা যায়


আমার অভিজ্ঞতার select(['_id'])চেয়ে দ্রুতselect()
জ্যান্টন

13

বড় সংগ্রহের জন্য নথি সংখ্যা গণনা সাবধান । আপনি যদি প্রতিটি সংকলনের জন্য পূর্বনির্ধারিত কাউন্টার রাখতে চান তবে ফায়ার স্টোর ডাটাবেসের সাথে এটি কিছুটা জটিল।

এই জাতীয় কোড এই ক্ষেত্রে কাজ করে না:

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/funitions/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'));

আপনি দেখতে পাচ্ছেন, একাধিক সম্পাদন রোধের মূল বিষয়টি প্রসঙ্গ অবজেক্টে ইভেন্টআইড নামে পরিচিত । যদি একই ইভেন্টের জন্য ফাংশনটি অনেক বার পরিচালনা করা হয় তবে ইভেন্টের আইডি সব ক্ষেত্রে একই হবে। দুর্ভাগ্যক্রমে, আপনার আপনার ডেটাবেজে "ইভেন্ট" সংগ্রহ থাকতে হবে।


2
তারা এই কথাটি এমনভাবে বাক্সবরণ করছে যে এই আচরণটি 1.0 টির প্রকাশে স্থির হবে। অ্যামাজন এডাব্লুএস ফাংশনগুলি একই সমস্যায় ভুগছে। গণনা ক্ষেত্রগুলি জটিল এবং ব্যয়বহুল হয়ে ওঠার সাথে এত সহজ কিছু।
মারকজি

এটি আরও ভাল সমাধান বলে মনে হচ্ছে বলে এটি এখনই চেষ্টা করে যাচ্ছেন। আপনি কি আবার ফিরে যান এবং কখনও আপনার ইভেন্ট সংগ্রহ মুছে ফেলেন? আমি কেবল একটি তারিখের ক্ষেত্র যোগ করার এবং ডেটা ছোট রাখার জন্য (সম্ভবত 1 মিলিল + ইভেন্ট / দিন) কেবল এক দিনের চেয়ে বেশি পুরানো বা কোনও কিছু পরিষ্কার করার কথা ভাবছিলাম। যদি এফএসের কোনও সহজ উপায় না হয় ... তবে কয়েক মাস ধরেই কেবল এফএস ব্যবহার করা হচ্ছে।
টাইম পোল্যাক

1
আমরা কি যাচাই করতে পারি যে context.eventIdএকই ট্রিগারটির একাধিক অনুরোধে সর্বদা একই থাকবে? আমার পরীক্ষায় এটি সামঞ্জস্যপূর্ণ বলে মনে হয়, তবে আমি এটি উল্লেখ করে কোনও "অফিসিয়াল" ডকুমেন্টেশন খুঁজে পাই না।
মাইক ম্যাকলিন

2
সুতরাং এটি কিছুক্ষণ ব্যবহার করার পরে, আমি খুঁজে পেয়েছি যে এই সমাধানটি ঠিক একটি লেখার সাথে কাজ করে, যা দুর্দান্ত, যদি একাধিক ডক্স একসাথে লেখা হচ্ছে এবং একই গণনা ডকটি আপডেট করার চেষ্টা করছে তবে অনেকগুলি যদি আগুনের সূত্রপাত করে তবে আপনি পারেন ফায়ারস্টোর থেকে বিতর্ক ত্রুটিগুলি পান। আপনি কি সেগুলির মুখোমুখি হয়েছিলেন এবং কীভাবে আপনি এটি ঘিরেছিলেন? (ত্রুটি: 10 গর্ভপাত: এই দস্তাবেজগুলিতে খুব বেশি বিতর্ক Please অনুগ্রহ করে আবার চেষ্টা করুন))
টিম পোল্যাক

1
@ টিমপল্যাক বিতরণ করা কাউন্টারে নথির লেখাগুলি দেখে প্রতি সেকেন্ডে প্রায় এক আপডেটের মধ্যে সীমাবদ্ধ
জ্যামি

8

2020 এ এটি এখনও ফায়ারবেস এসডিকে উপলভ্য নয় তবে এটি ফায়ারবেস এক্সটেনশনস (বিটা) এ পাওয়া যায় তবে এটি সেটআপ এবং ব্যবহার করা বেশ জটিল ...

একটি যুক্তিসঙ্গত পন্থা

সহায়কগণ ... (তৈরি / মুছে ফেলা অপ্রয়োজনীয় বলে মনে হয় তবে এটি অন-আপডেটের তুলনায় সস্তা)

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'));

এটি কি "প্রতি সেকেন্ডে 1 টি ডকুমেন্ট আপডেট" একই সীমাবদ্ধতার শিকার হয় না?
আইয়্যাপ্প

হ্যাঁ, তবে এটি শেষ পর্যন্ত সামঞ্জস্যপূর্ণ, অর্থ সংগ্রহের গণনা অবশেষে প্রকৃত সংগ্রহের গণনার সাথে একত্রিত হবে, এটি বাস্তবায়নের সবচেয়ে সহজ সমাধান এবং অনেক ক্ষেত্রে সংখ্যায় একটি সংক্ষিপ্ত ব্যবধান গ্রহণযোগ্য।
বেন উইন্ডিং

7

আমি @ মাতৃর সাথে একমত, আপনি যদি এই জাতীয় কোয়েরি করেন তবে অনেক খরচ হবে cost

[তাদের প্রকল্পগুলি শুরু করার আগে বিকাশকারীদের জন্য পরামর্শ]

যেহেতু আমরা শুরুতে এই পরিস্থিতিটি আগে থেকেই দেখেছি, আমরা প্রকৃতপক্ষে একটি ক্ষেত্রের মধ্যে সমস্ত কাউন্টারগুলিকে টাইপ করে সংরক্ষণ করার জন্য একটি নথি সহ একটি সংগ্রহ তৈরি করতে পারি number

উদাহরণ স্বরূপ:

সংগ্রহের প্রতিটি সিআরইউডি অপারেশনের জন্য, কাউন্টার ডকুমেন্টটি আপডেট করুন:

  1. আপনি যখন একটি নতুন সংগ্রহ / উপকোলেকশন তৈরি করবেন : (কাউন্টারে +1) [1 রাইটিং অপারেশন]
  2. আপনি যখন কোনও সংগ্রহ / উপবিভাজন মুছবেন : (কাউন্টারে -1) [1 রাইটিং অপারেশন]
  3. আপনি যখন কোনও বিদ্যমান সংগ্রহ / উপ-সংগ্রহ আপডেট করেন তখন কাউন্টার ডকুমেন্টে কিছু করবেন না: (0)
  4. আপনি যখন কোনও বিদ্যমান সংগ্রহ / উপ-সংগ্রহটি পড়েন তখন কাউন্টার ডকুমেন্টে কিছু করবেন না: (0)

পরের বার, আপনি যখন সংগ্রহের সংখ্যা পেতে চান, আপনার কেবল ডকুমেন্টের ক্ষেত্রের দিকে প্রশ্ন / পয়েন্ট করতে হবে। [১ টি অপারেশন]

এছাড়াও, আপনি সংগ্রহের নাম একটি অ্যারেতে সঞ্চয় করতে পারেন, তবে এটি কৌশলটি জটিল হবে, ফায়ারবেসে অ্যারের শর্তটি নীচের মত দেখানো হয়েছে:

// 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'}

সুতরাং, আপনি যদি সংগ্রহটি মুছে ফেলতে যাচ্ছেন না, আপনি প্রতিবার সমস্ত সংগ্রহ জিজ্ঞাসা না করে সংগ্রহের নামের তালিকা সংরক্ষণ করতে অ্যারে ব্যবহার করতে পারেন।

আশা করি এটা সাহায্য করবে!


একটি ছোট সংগ্রহের জন্য, সম্ভবত। তবে মনে রাখবেন ফায়ারস্টোর ডকুমেন্টের আকারের সীমাটি M 1MB, যা যদি কোনও সংগ্রহের নথির আইডিগুলি স্বয়ংক্রিয়ভাবে উত্পাদিত হয় (20 বাইট), তবে আপনি কেবলমাত্র এগুলির মধ্যে, 52,425 সঞ্চয় করতে পারবেন খুব বড়। আমি অনুমান করি যে আপনি প্রতি 50,000 উপাদানগুলিতে একটি নতুন ডক তৈরি করতে পারেন, তবে তারপরে এই অ্যারেগুলি বজায় রাখা পুরোপুরি নিয়ন্ত্রণহীন। আরও, দস্তাবেজের আকার বাড়ার সাথে সাথে এটি পড়তে এবং আপডেট করতে আরও বেশি সময় লাগবে, যা শেষ পর্যন্ত বিতর্কিত হয়ে অন্য কোনও ক্রিয়াকলাপ তৈরি করবে।
টিম পোল্যাক

5

না, এখনই একীকরণের প্রশ্নের জন্য কোনও অন্তর্নির্মিত সমর্থন নেই। তবে কয়েকটি জিনিস আপনি করতে পারেন।

প্রথম এখানে নথিভুক্ত করা হয় । আপনি সামগ্রিক তথ্য বজায় রাখতে লেনদেন বা মেঘ ফাংশন ব্যবহার করতে পারেন:

এই উদাহরণটি দেখায় যে উপ-সংগ্রহের পাশাপাশি গড় রেটিংয়ের রেটিংয়ের সংখ্যা ট্র্যাক রাখতে কোনও ফাংশন কীভাবে ব্যবহার করতে হয়।

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()কেবলমাত্র সার্ভার এসডিকেগুলিতে এখনই উপলভ্য যাতে সমাধানটি কোনও মোবাইল অ্যাপ্লিকেশনে কাজ করবে না।


1
এই সমাধানটি আদর্শবান নয়, সুতরাং যে কোনও ট্রিগার একবারে একাধিকবার আগুন জ্বলে তা আপনার রেটিং এবং গড় সংখ্যাটি ফেলে দেয়।
টিম পোল্যাক

4

সরাসরি কোনও বিকল্প উপলব্ধ নেই। আপনি করতে পারবেন না db.collection("CollectionName").count()। নীচে দুটি উপায় যা দিয়ে আপনি সংগ্রহের মধ্যে নথির সংখ্যা গণনা করতে পারেন।

1: - সংগ্রহের সমস্ত নথি পান এবং তার আকার পান get (সেরা সমাধান নয়)

db.collection("CollectionName").get().subscribe(doc=>{
console.log(doc.size)
})

উপরের কোডটি ব্যবহার করে আপনার দস্তাবেজটি পড়তে হবে কোনও সংগ্রহের মধ্যে দস্তাবেজের আকারের সমান এবং সে কারণেই কোনও ব্যক্তিকে উপরের সমাধানটি ব্যবহার করা এড়াতে হবে।

2: - আপনার সংগ্রহে একটি পৃথক নথি তৈরি করুন যা সংগ্রহের নথির সংখ্যা গণনা করবে will (সেরা সমাধান)

db.collection("CollectionName").doc("counts")get().subscribe(doc=>{
console.log(doc.count)
})

উপরে আমরা সমস্ত গণনা তথ্য সংরক্ষণ করার জন্য নাম গণনা সহ একটি নথি তৈরি করেছি You আপনি নিম্নলিখিত উপায়ে গণনা ডকুমেন্টটি আপডেট করতে পারেন: -

  • দস্তাবেজের গুনে ফায়ারস্টোর ট্রিগার তৈরি করুন
  • একটি নতুন দস্তাবেজ তৈরি করা হয় গণনা নথির গণনা সম্পত্তি বৃদ্ধি।
  • নথি মুছে ফেলা হলে গণনা নথির গণনা সম্পত্তি হ্রাস করুন।

আরআরটি দাম (ডকুমেন্ট রিড = 1) এবং দ্রুত ডেটা পুনরুদ্ধার উপরের সমাধানটি ভাল।


3

অ্যাডমিন.ফায়ার স্টোর.ফিল্ডভ্যালু.ইনক্রিমেন্ট ব্যবহার করে একটি কাউন্টার বাড়ান :

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আপডেটগুলি কল করবেন যার অর্থ আপনি অপ্রয়োজনীয় ফাংশন আমন্ত্রণের জন্য বেশি অর্থ ব্যয় করছেন (যদি আপনি আপনার সংগ্রহে ডক্সগুলি আপডেট করেন)।


2

একটি কার্যনির্বাহীটি হ'ল:

ফায়ারবেস ডকটিতে একটি কাউন্টার লিখুন, যা আপনি প্রতিবার একটি নতুন এন্ট্রি তৈরির সময় লেনদেনের মধ্যে বৃদ্ধি করেন

আপনি আপনার নতুন প্রবেশের একটি ক্ষেত্রে গণনা সংরক্ষণ করুন (যেমন: অবস্থান: 4)।

তারপরে আপনি সেই ক্ষেত্রটিতে একটি সূচক তৈরি করুন (অবস্থান ডিইএসসি)।

আপনি একটি ক্যোয়ারী সহ একটি স্কিপ + সীমাবদ্ধতা করতে পারেন W যেখানে ("অবস্থান", "<" এক্স) rdআর্ডার বাই ("অবস্থান", ডিইএসসি)

আশাকরি এটা সাহায্য করবে!


1

আমি সমস্ত পাল্টা পরিস্থিতিগুলি (ক্যোয়ারী ব্যতীত) পরিচালনা করতে এই সমস্ত ধারণাগুলি ব্যবহার করে একটি সর্বজনীন ফাংশন তৈরি করেছি।

একমাত্র ব্যতিক্রম হ'ল যখন অনেকগুলি সেকেন্ড লেখেন তখন তা আপনাকে ধীর করে দেয়। একটি উদাহরণ ট্রেন্ডিং পোস্টে পছন্দ হবে । উদাহরণস্বরূপ এটি একটি ব্লগ পোস্টে ওভারকিল, এবং আপনার জন্য আরও বেশি ব্যয় হবে। আমি শারডগুলি ব্যবহার করে সেই ক্ষেত্রে একটি পৃথক ফাংশন তৈরি করার পরামর্শ দিচ্ছি: 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);
        });;
    }
}

এটি ইভেন্ট, ইনক্রিমেন্ট এবং লেনদেন পরিচালনা করে। এর সৌন্দর্যটি হ'ল আপনি যদি কোনও নথির যথার্থতা সম্পর্কে নিশ্চিত না হন (সম্ভবত বিটা থাকাকালীনও), আপনি পরবর্তী কাউকে এটি স্বয়ংক্রিয়ভাবে পরবর্তী ট্রিগারটিতে যুক্ত করার জন্য কাউন্টারটি মুছতে পারেন। হ্যাঁ, এই ব্যয়গুলি, তাই অন্যথায় এটি মুছবেন না।

গণনা পেতে একই ধরণের জিনিস:

const collectionPath = 'buildings/138faicnjasjoa89/buildingContacts';
const colSnap = await db.doc('_counters/' + collectionPath).get();
const count = colSnap.get('count');

এছাড়াও, আপনি ডাটাবেস স্টোরেজে অর্থ সাশ্রয়ের জন্য পুরানো ইভেন্টগুলি সরাতে ক্রোন জব (নির্ধারিত ফাংশন) তৈরি করতে চাইতে পারেন। আপনার কমপক্ষে একটি জ্বলন পরিকল্পনা দরকার এবং আরও কিছু কনফিগারেশন থাকতে পারে। উদাহরণস্বরূপ, আপনি প্রতি রবিবার এগারোটায় এটি চালাতে পারেন। 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;
    });

এবং সর্বশেষে, ফায়ারস্টোর.রুলসগুলিতে সংগ্রহগুলি সুরক্ষিত করতে ভুলবেন না :

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;
}

আমার এও আপনাকে সতর্ক করে দেওয়া উচিত যে সর্বজনীন ফাংশন প্রতিটি অনরাইট কল পিরিয়ডে চলবে। কেবলমাত্র অনক্রিট এবং আপনার নির্দিষ্ট সংগ্রহের অনডিলিট ইভেন্টগুলিতে ফাংশনটি চালানো সস্তা হবে। আমরা যে এনএসকিউএল ডাটাবেসটি ব্যবহার করছি তার মতো, বারবার কোড এবং ডেটা আপনার অর্থ সাশ্রয় করতে পারে।


সহজ অ্যাক্সেসের জন্য এটি সম্পর্কে একটি নিবন্ধ লিখুন।
আহমাদালিবালোচ


0

উপরের কয়েকটি উত্তরের উপর ভিত্তি করে এই কাজটি করতে আমাকে কিছুটা সময় নিয়েছে, তাই আমি ভেবেছিলাম এটি অন্যের ব্যবহারের জন্য ভাগ করে নেব। আমি আশা করি এটি কার্যকর

'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;
});

0

আমি বিভিন্ন পদ্ধতির সাথে অনেক চেষ্টা করেছি। এবং পরিশেষে, আমি একটি পদ্ধতির উন্নতি করি। প্রথমে আপনাকে একটি পৃথক সংগ্রহ তৈরি করতে হবে এবং সেখানে সমস্ত ইভেন্ট সংরক্ষণ করতে হবে। দ্বিতীয়ত আপনাকে সময় দ্বারা ট্রিগার করার জন্য একটি নতুন ল্যাম্বডা তৈরি করতে হবে। এই ল্যাম্বদা ইভেন্ট সংগ্রহ এবং ইভেন্টের দস্তাবেজগুলিতে ইভেন্টগুলি গণনা করবে। নিবন্ধে কোড বিশদ। https://medium.com/@ihor.malaniuk/how-to-count-documents-in-google-cloud-firestore-b0e65863aeca


দয়া করে উত্তরে প্রাসঙ্গিক বিশদ এবং কোড অন্তর্ভুক্ত করুন , আপনার ব্লগ পোস্টগুলিতে লোককে নির্দেশ করা আসলে স্ট্যাকওভারফ্লোয়ের বিন্দু নয়।
ডিবিএস

0

এই ক্যোয়ারির ফলে নথির গণনা হবে।

this.db.collection(doc).get().subscribe((data) => {
      count = data.docs.length;
    });

console.log(count)

1
আপনি প্রতি বার সংগ্রহ থেকে সমস্ত দস্তাবেজ আনছেন বলে একটি ভাল সমাধান নয়। এতে অনেক খরচ হবে। এই সংগ্রহটিতে প্রতিবার নতুন দস্তাবেজ যুক্ত হওয়ার সাথে সাথে একটি কাউন্টার সেটআপ করা আরও ভাল পদ্ধতির যাতে আপনি কয়েক হাজারের পরিবর্তে কেবল একটি নথি আনতে পারেন।
কোরেণ্টিন হুডায়ার

0

এটি সংখ্যার অনন্য আইডি তৈরি করতে গণনা ব্যবহার করে। আমার ব্যবহারে, আমি কখনই হ্রাস পাচ্ছি না , এমনকি documentআইডিটি মুছে ফেলা হলেও।

এমন এক collectionক্রিয়েশনের জন্য যার অনন্য সংখ্যার মান প্রয়োজন needs

  1. একটি সংগ্রহ নির্দিষ্ট করুন appDataএক নথিতে সঙ্গে, setসঙ্গে .docআইডিonly
  2. সেট uniqueNumericIDAmount মধ্যে 0 তে করুনfirebase firestore console
  3. ব্যবহার doc.data().uniqueNumericIDAmount + 1অনন্য সংখ্যা আইডি হিসাবে
  4. সাথে appDataসংগ্রহ আপডেট করুনuniqueNumericIDAmountfirebase.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);
            });
    });

-1
firebaseFirestore.collection("...").addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {

            int Counter = documentSnapshots.size();

        }
    });

1
এই উত্তরটি কোড উদাহরণ হিসাবে আরও প্রসঙ্গ ব্যবহার করতে পারে।
শেলনিজা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.