CouchDB
 sql >> डेटाबेस >  >> NoSQL >> CouchDB

हसुरा के साथ पोस्टग्रेज पर कॉच डीबी स्टाइल सिंक और संघर्ष समाधान

हम ऑफ़लाइन के बारे में बात कर रहे हैं-पहले हसुरा और आरएक्सडीबी (अनिवार्य रूप से नीचे पोस्टग्रेज और पाउचडीबी) के साथ।

यह पोस्ट विषय में गहराई से गोता लगाने के लिए जारी है। यह पोस्टग्रेज़ (केंद्रीय बैकएंड डेटाबेस) और पाउचडीबी (फ्रंटएंड ऐप उपयोगकर्ता के साथ कॉच डीबी शैली संघर्ष समाधान को लागू करने के लिए एक चर्चा और मार्गदर्शिका है। डेटाबेस)।

यहाँ हम किस बारे में बात करने जा रहे हैं:

  • संघर्ष समाधान क्या है?
  • क्या मेरे ऐप को विरोध समाधान की आवश्यकता है?
  • PouchDB के साथ संघर्ष समाधान समझाया गया
  • आरएक्सडीबी और हसुरा के साथ पाउचडीबी (फ्रंटएंड) और पोस्टग्रेज (बैकएंड) में आसान प्रतिकृति और संघर्ष प्रबंधन लाना
    • हसुरा की स्थापना
    • क्लाइंट साइड सेटअप
    • संघर्ष समाधान लागू करना
    • दृश्यों का उपयोग करना
    • पोस्टग्रेज ट्रिगर का उपयोग करना
  • हसुरा के साथ कस्टम संघर्ष समाधान रणनीतियाँ
    • सर्वर पर कस्टम विरोध समाधान
    • क्लाइंट पर कस्टम विरोध समाधान
  • निष्कर्ष

विरोध समाधान क्या है?

आइए एक उदाहरण के रूप में ट्रेलो बोर्ड को लें। मान लें कि आपने ऑफ़लाइन रहते हुए किसी ट्रेलो कार्ड पर असाइनी को बदल दिया है। इस बीच आपका सहयोगी उसी कार्ड के विवरण को संपादित करता है। जब आप ऑनलाइन वापस आएंगे तो आप दोनों बदलाव देखना चाहेंगे। अब मान लीजिए आप दोनों ने एक ही समय में विवरण बदल दिया, तो इस मामले में क्या होना चाहिए? एक विकल्प केवल अंतिम लेखन को लेना है - जो कि नए के साथ पहले के परिवर्तन को ओवरराइड करता है। दूसरा उपयोगकर्ता को सूचित करना और उन्हें मर्ज किए गए फ़ील्ड (जैसे git!) के साथ कार्ड को अपडेट करने देना है।

एक साथ कई परिवर्तन (जो परस्पर विरोधी हो सकते हैं) लेने और उन्हें एक परिवर्तन में विलय करने के इस पहलू को संघर्ष समाधान कहा जाता है।

जब आपके पास अच्छी प्रतिकृति और विरोध समाधान क्षमताएं हों तो आप किस प्रकार के ऐप्स बना सकते हैं?

किसी एप्लिकेशन के फ्रंटएंड और बैकएंड में निर्माण करने के लिए प्रतिकृति और संघर्ष समाधान बुनियादी ढांचा दर्दनाक है। लेकिन एक बार यह सेटअप हो जाने के बाद, कुछ महत्वपूर्ण उपयोग-मामले व्यवहार्य हो जाते हैं! वास्तव में, कुछ प्रकार के अनुप्रयोगों के लिए प्रतिकृति (और इसलिए संघर्ष समाधान) ऐप की कार्यक्षमता के लिए महत्वपूर्ण हैं!

  1. रीयलटाइम:विभिन्न उपकरणों पर उपयोगकर्ताओं द्वारा किए गए परिवर्तन एक दूसरे के साथ समन्वयित होते हैं
  2. सहयोगी:अलग-अलग उपयोगकर्ता एक साथ एक ही डेटा पर काम करते हैं
  3. ऑफ़लाइन-प्रथम:वही उपयोगकर्ता अपने डेटा के साथ काम कर सकता है, भले ही ऐप केंद्रीय डेटाबेस से कनेक्ट न हो

उदाहरण:ट्रेलो, ईमेल क्लाइंट जैसे जीमेल, सुपरह्यूमन, गूगल डॉक्स, फेसबुक, ट्विटर आदि।

हसुरा आपके मौजूदा पोस्टग्रेज आधारित एप्लिकेशन में उच्च-प्रदर्शन, सुरक्षित, रीयलटाइम क्षमताओं को जोड़ना बेहद आसान बनाता है। इन उपयोग-मामलों का समर्थन करने के लिए अतिरिक्त बैकएंड बुनियादी ढांचे को तैनात करने की आवश्यकता नहीं है! अगले कुछ अनुभागों में हम सीखेंगे कि आप फ्रंटएंड पर PouchDB/RxDB का उपयोग कैसे कर सकते हैं और इसे हसुरा के साथ जोड़कर शानदार उपयोगकर्ता-अनुभव के साथ शक्तिशाली ऐप्स बना सकते हैं।

PouchDB के साथ संघर्ष समाधान समझाया गया

PouchDB के साथ संस्करण प्रबंधन

PouchDB - जिसका RxDB नीचे उपयोग करता है - एक शक्तिशाली संस्करण और संघर्ष प्रबंधन तंत्र के साथ आता है। PouchDB के प्रत्येक दस्तावेज़ में इसके साथ संबद्ध एक संस्करण फ़ील्ड होता है। वर्शन फ़ील्ड <depth>-<object-hash> . के रूप में हैं उदाहरण के लिए 2-c1592ce7b31cc26e91d2f2029c57e621 . यहां गहराई संशोधन वृक्ष में गहराई को इंगित करती है। ऑब्जेक्ट हैश एक बेतरतीब ढंग से उत्पन्न स्ट्रिंग है।

PouchDB संशोधनों की एक झलक

PouchDB किसी दस्तावेज़ के संशोधन इतिहास को लाने के लिए API को उजागर करता है। हम संशोधन इतिहास को इस प्रकार क्वेरी कर सकते हैं:

todos.pouch.get(todo.id, {
    revs: true
})

यह एक _revisions . वाला दस्तावेज़ लौटाएगा खेत:

{
  "id": "559da26d-ad0f-42bc-a172-1821641bf2bb",
  "_rev": "4-95162faab173d1e748952179e0db1a53",
  "_revisions": {
    "ids": [
      "95162faab173d1e748952179e0db1a53",
      "94162faab173d1e748952179e0db1a53",
      "9055e63d99db056a95b61936f0185c8c",
      "de71900ec14567088bed5914b2439896"
    ],
    "start": 4
  }
}

यहां ids संशोधनों के संशोधन (वर्तमान सहित) और start . का पदानुक्रम शामिल है वर्तमान संशोधन के लिए "उपसर्ग संख्या" शामिल है। हर बार एक नया संशोधन जोड़ा जाता है start वृद्धि हुई है और ids . की शुरुआत में एक नया हैश जोड़ा गया है सरणी।

जब कोई दस्तावेज़ किसी दूरस्थ सर्वर से समन्वयित किया जाता है, _revisions और _rev क्षेत्रों को शामिल करना होगा। इस तरह सभी क्लाइंट के पास अंततः पूर्ण संस्करण इतिहास होता है। यह स्वचालित रूप से तब होता है जब पाउचडीबी को कॉच डीबी के साथ सिंक करने के लिए स्थापित किया जाता है। उपरोक्त पुल अनुरोध ग्राफक्यूएल के माध्यम से भी समन्वयित करते समय इसे सक्षम करता है।

ध्यान दें कि जरूरी नहीं कि सभी क्लाइंट के पास सभी संशोधन हों, लेकिन उन सभी के पास अंततः नवीनतम संस्करण और इन संस्करणों के लिए संशोधन आईडी का इतिहास होगा।

विरोध समाधान

एक विरोध का पता लगाया जाएगा यदि दो संशोधनों में एक ही माता-पिता हैं या अधिक सरलता से यदि किन्हीं दो संशोधनों की गहराई समान है। जब किसी विरोध का पता चलता है, तो CouchDB और PouchDB विजेता को स्वतः चुनने के लिए समान एल्गोरिथम का उपयोग करेंगे:

  1. उच्चतम गहराई वाले फ़ील्ड वाले संशोधन चुनें जिन्हें हटाए गए के रूप में चिह्नित नहीं किया गया है
  2. यदि ऐसा केवल 1 क्षेत्र है, तो इसे विजेता के रूप में मानें
  3. यदि 1 से अधिक हैं, तो संशोधन फ़ील्ड को अवरोही क्रम में क्रमबद्ध करें और पहले वाले को चुनें।

हटाने के बारे में एक नोट: PouchDB और CouchDB कभी भी संशोधन या दस्तावेज़ नहीं हटाते हैं, इसके बजाय _deleted ध्वज को सत्य पर सेट करके एक नया संशोधन बनाया जाता है। इसलिए उपरोक्त एल्गोरिथम के चरण 1 में हटाए गए के रूप में चिह्नित संशोधन के साथ समाप्त होने वाली किसी भी श्रृंखला को अनदेखा कर दिया जाता है।

इस एल्गोरिथम की एक अच्छी विशेषता यह है कि किसी विरोध को हल करने के लिए क्लाइंट या क्लाइंट और सर्वर के बीच किसी समन्वय की आवश्यकता नहीं होती है। किसी संस्करण को विजेता के रूप में चिह्नित करने के लिए किसी अतिरिक्त मार्कर की आवश्यकता नहीं है। प्रत्येक क्लाइंट और सर्वर स्वतंत्र रूप से विजेता चुनते हैं। लेकिन विजेता वही संशोधन होगा क्योंकि वे समान नियतात्मक एल्गोरिथम का उपयोग करते हैं। भले ही क्लाइंट में से किसी एक में कुछ संशोधन गायब हों, अंततः जब उन संशोधनों को समन्वयित किया जाता है, तो वही संशोधन विजेता के रूप में चुना जाता है।

कस्टम संघर्ष समाधान रणनीतियों को लागू करना

लेकिन क्या होगा अगर हम एक वैकल्पिक संघर्ष समाधान रणनीति चाहते हैं? उदाहरण के लिए "फ़ील्ड द्वारा मर्ज करें" - यदि दो परस्पर विरोधी संशोधनों ने ऑब्जेक्ट की विभिन्न कुंजियों को संशोधित किया है, तो हम दोनों कुंजियों के साथ एक संशोधन बनाकर ऑटो मर्ज करना चाहते हैं। PouchDB में ऐसा करने का अनुशंसित तरीका है:

  1. किसी भी श्रृंखला पर यह नया संशोधन बनाएं
  2. प्रत्येक अन्य शृंखला में _deleted set to true के साथ एक संशोधन जोड़ें

मर्ज किए गए संशोधन अब उपरोक्त एल्गोरिथम के अनुसार स्वचालित रूप से विजेता संशोधन होंगे। हम सर्वर या क्लाइंट पर कस्टम रिज़ॉल्यूशन कर सकते हैं। जब संशोधन सभी क्लाइंट को सिंक कर देते हैं और सर्वर मर्ज किए गए संशोधन को विजेता संशोधन के रूप में देखेगा।

हसुरा और RxDB के साथ संघर्ष समाधान

उपरोक्त संघर्ष समाधान रणनीति को लागू करने के लिए, हमें हसुरा को संशोधन इतिहास को संग्रहीत करने की आवश्यकता होगी और आरएक्सडीबी के लिए ग्राफक्यूएल का उपयोग करते हुए संशोधनों को सिंक करने के लिए।

हसुरा सेट अप करना

पिछली पोस्ट से टोडो ऐप उदाहरण के साथ जारी है। हमें टोडोस तालिका के लिए स्कीमा को निम्नानुसार अपडेट करना होगा:

todo (
  id: text primary key,
  userId: text,
  text: text, <br/>
  createdAt: timestamp,
  isCompleted: boolean,
  deleted: boolean,
  updatedAt: boolean,
  _revisions: jsonb,
  _rev: text primary key,
  _parent_rev: text,
  _depth: integer,
)

अतिरिक्त क्षेत्रों पर ध्यान दें:

  • _rev रिकॉर्ड के संशोधन का प्रतिनिधित्व करता है।
  • _parent_rev रिकॉर्ड के मूल संशोधन का प्रतिनिधित्व करता है
  • _depth रिवीजन ट्री में रिकॉर्ड की गहराई है
  • _revisions रिकॉर्ड के संशोधन का पूरा इतिहास शामिल है।

तालिका के लिए प्राथमिक कुंजी है (id , _rev )।

कड़ाई से बोलते हुए हमें केवल _revisions . की आवश्यकता है क्षेत्र क्योंकि अन्य जानकारी इससे प्राप्त की जा सकती है। लेकिन अन्य फ़ील्ड आसानी से उपलब्ध होने से संघर्ष का पता लगाना और समाधान आसान हो जाता है।

क्लाइंट साइड सेटअप

हमें syncRevisions set सेट करने की आवश्यकता है प्रतिकृति स्थापित करते समय सत्य के लिए


    async setupGraphQLReplication(auth) {
        const replicationState = this.db.todos.syncGraphQL({
            url: syncURL,
            headers: {
                'Authorization': `Bearer ${auth.idToken}`
            },
            push: {
                batchSize,
                queryBuilder: pushQueryBuilder
            },
            pull: {
                queryBuilder: pullQueryBuilder(auth.userId)
            },

            live: true,

            liveInterval: 1000 * 60 * 10,
            deletedFlag: 'deleted',
            syncRevisions: true,
        });

       ...
    }

हमें एक टेक्स्ट फ़ील्ड last_pulled_rev . भी जोड़ने की आवश्यकता है RxDB स्कीमा के लिए। सर्वर से वापस सर्वर पर लाए गए संशोधनों को आगे बढ़ाने से बचने के लिए इस फ़ील्ड का उपयोग प्लगइन द्वारा आंतरिक रूप से किया जाता है।

const todoSchema = {
    ...
    'properties': {
        ...
        'last_pulled_rev': {
            'type': 'string'
        }
    },
    ...
};

अंत में, हमें संशोधन संबंधी जानकारी को सिंक करने के लिए पुल और पुश क्वेरी बिल्डरों को बदलने की जरूरत है

क्वेरी निर्माता खींचें

const pullQueryBuilder = (userId) => {
    return (doc) => {
        if (!doc) {
            doc = {
                id: '',
                updatedAt: new Date(0).toUTCString()
            };
        }

        const query = `{
            todos(
                where: {
                    _or: [
                        {updatedAt: {_gt: "${doc.updatedAt}"}},
                        {
                            updatedAt: {_eq: "${doc.updatedAt}"},
                            id: {_gt: "${doc.id}"}
                        }
                    ],
                    userId: {_eq: "${userId}"} 
                },
                limit: ${batchSize},
                order_by: [{updatedAt: asc}, {id: asc}]
            ) {
                id
                text
                isCompleted
                deleted
                createdAt
                updatedAt
                userId
                _rev
                _revisions
            }
        }`;
        return {
            query,
            variables: {}
        };
    };
};

अब हम _rev और _revisions फ़ील्ड लाते हैं। अपग्रेड किया गया प्लग इन इन क्षेत्रों का उपयोग स्थानीय PouchDB संशोधन बनाने के लिए करेगा।

पुश क्वेरी बिल्डर


const pushQueryBuilder = doc => {
    const query = `
        mutation InsertTodo($todo: [todos_insert_input!]!) {
            insert_todos(objects: $todo){
                returning {
                  id
                }
            }
       }
    `;

    const depth = doc._revisions.start;
    const parent_rev = depth == 1 ? null : `${depth - 1}-${doc._revisions.ids[1]}`

    const todo = Object.assign({}, doc, {
        _depth: depth,
        _parent_rev: parent_rev
    })

    delete todo['updatedAt']

    const variables = {
        todo: todo
    };

    return {
        query,
        variables
    };
};

अपग्रेड किए गए प्लगइन के साथ, इनपुट पैरामीटर doc अब इसमें शामिल है _rev और _revisions खेत। हम ग्राफ़क्यूएल क्वेरी में हसुरा को पास करते हैं। हम फ़ील्ड जोड़ते हैं _depth , _parent_rev doc . को ऐसा करने से पहले।

पहले हम एक todo . डालने या अपडेट करने के लिए अप्सर्ट का उपयोग कर रहे थे हसुरा पर रिकॉर्ड अब चूंकि प्रत्येक संस्करण एक नया रिकॉर्ड बन जाता है, इसलिए हम इसके बजाय सादे पुराने इंसर्ट म्यूटेशन का उपयोग करते हैं।

विरोध समाधान लागू करना

यदि दो अलग-अलग क्लाइंट अब परस्पर विरोधी परिवर्तन करते हैं तो दोनों संशोधन समन्वयित हो जाएंगे और हसुरा में मौजूद होंगे। दोनों ग्राहकों को अंततः अन्य संशोधन भी प्राप्त होंगे। चूंकि पाउचडीबी की संघर्ष समाधान रणनीति नियतात्मक है, इसलिए दोनों क्लाइंट "विजेता संशोधन" के समान संस्करण को चुनेंगे।

हम सर्वर पर इस विजेता संशोधन को कैसे ढूंढ सकते हैं? हमें SQL में समान एल्गोरिदम लागू करना होगा।

Postgres पर CouchDB के संघर्ष समाधान एल्गोरिदम को लागू करना

चरण 1:हटाए गए के रूप में चिह्नित नहीं लीफ़ नोड्स ढूँढना

ऐसा करने के लिए हमें ऐसे किसी भी संस्करण को अनदेखा करने की आवश्यकता है जिसमें बाल संशोधन है और कोई भी संस्करण जिसे हटाए गए के रूप में चिह्नित किया गया है:

    SELECT
        id,
        _rev,
        _depth
    FROM
        todos
    WHERE
        NOT EXISTS (
            SELECT
                id
            FROM
                todos AS t
            WHERE
                todos.id = t.id
                AND t._parent_rev = todos._rev)
            AND deleted = FALSE

चरण 2:अधिकतम गहराई के साथ श्रृंखला ढूँढना

यह मानते हुए कि हमारे पास उपरोक्त क्वेरी के परिणाम एक तालिका (या दृश्य या खंड के साथ) में हैं, जिन्हें हम पत्ते कह सकते हैं, हम अधिकतम गहराई वाली श्रृंखला को सीधे आगे पा सकते हैं:

    SELECT
        id,
        MAX(_depth) AS max_depth
    FROM
        leaves
    GROUP BY
        id

चरण 3:समान अधिकतम गहराई वाले संशोधनों के बीच विजेता संशोधन ढूंढना

फिर से यह मानते हुए कि उपरोक्त क्वेरी के परिणाम एक तालिका (या एक दृश्य या खंड के साथ) में हैं, जिन्हें max_depths कहा जाता है, हम निम्नानुसार विजेता संशोधन पा सकते हैं:

    SELECT
        leaves.id,
        MAX(leaves._rev) AS _rev
    FROM
        leaves
        JOIN max_depths ON leaves.id = max_depths.id
            AND leaves._depth = max_depths.max_depth
    GROUP BY
        leaves.id

जीतने वाले संशोधनों के साथ एक दृश्य बनाना

उपरोक्त तीन प्रश्नों को एक साथ रखकर हम एक ऐसा दृश्य बना सकते हैं जो हमें निम्न प्रकार से विजेता संशोधन दिखाता है:

CREATE OR REPLACE VIEW todos_current_revisions AS
WITH leaves AS (
    SELECT
        id,
        _rev,
        _depth
    FROM
        todos
    WHERE
        NOT EXISTS (
            SELECT
                id
            FROM
                todos AS t
            WHERE
                todos.id = t.id
                AND t._parent_rev = todos._rev)
            AND deleted = FALSE
),
max_depths AS (
    SELECT
        id,
        MAX(_depth) AS max_depth
    FROM
        leaves
    GROUP BY
        id
),
winning_revisions AS (
    SELECT
        leaves.id,
        MAX(leaves._rev) AS _rev
    FROM
        leaves
        JOIN max_depths ON leaves.id = max_depths.id
            AND leaves._depth = max_depths.max_depth
    GROUP BY
        (leaves.id))
SELECT
    todos.*
FROM
    todos
    JOIN winning_revisions ON todos._rev = winning_revisions._rev;

चूंकि हसुरा विचारों को ट्रैक कर सकता है और उन्हें ग्राफ़क्यूएल के माध्यम से क्वेरी करने की अनुमति देता है, इसलिए जीतने वाले संशोधन अब अन्य ग्राहकों और सेवाओं के सामने आ सकते हैं।

जब भी आप दृश्य को क्वेरी करते हैं, तो Postgres केवल दृश्य परिभाषा में क्वेरी के साथ दृश्य को बदल देगा और परिणामी क्वेरी चलाएगा। यदि आप बार-बार दृश्य को क्वेरी करते हैं तो यह समाप्त हो सकता है जिससे बहुत सारे CPU चक्र बर्बाद हो जाते हैं। हम पोस्टग्रेज ट्रिगर्स का उपयोग करके और जीतने वाले संशोधनों को एक अलग तालिका में संग्रहीत करके इसे अनुकूलित कर सकते हैं।

विजेता संशोधनों की गणना के लिए पोस्टग्रेज ट्रिगर का उपयोग करना

चरण 1:todos_current_revisions के लिए एक नई तालिका बनाएं

स्कीमा todos . की तरह ही होगा टेबल। हालांकि, प्राथमिक कुंजी id होगी (id, _rev) . के बजाय कॉलम

चरण 2:पोस्टग्रेज ट्रिगर बनाएं

हम व्यू क्वेरी से शुरू करके ट्रिगर के लिए क्वेरी लिख सकते हैं। चूंकि ट्रिगर फ़ंक्शन एक समय में एक पंक्ति के लिए चलेगा, हम क्वेरी को सरल बना सकते हैं:

CREATE OR REPLACE FUNCTION calculate_winning_revision ()
    RETURNS TRIGGER
    AS $BODY$
BEGIN
    INSERT INTO todos_current_revisions WITH leaves AS (
        SELECT
            id,
            _rev,
            _depth
        FROM
            todos
        WHERE
            NOT EXISTS (
                SELECT
                    id
                FROM
                    todos AS t
                WHERE
                    t.id = NEW.id
                    AND t._parent_rev = todos._rev)
                AND deleted = FALSE
                AND id = NEW.id
        ),
        max_depths AS (
            SELECT
                MAX(_depth) AS max_depth
            FROM
                leaves
        ),
        winning_revisions AS (
            SELECT
                MAX(leaves._rev) AS _rev
            FROM
                leaves
                JOIN max_depths ON leaves._depth = max_depths.max_depth
        )
        SELECT
            todos.*
        FROM
            todos
            JOIN winning_revisions ON todos._rev = winning_revisions._rev
    ON CONFLICT ON CONSTRAINT todos_winning_revisions_pkey
        DO UPDATE SET
            _rev = EXCLUDED._rev,
            _revisions = EXCLUDED._revisions,
            _parent_rev = EXCLUDED._parent_rev,
            _depth = EXCLUDED._depth,
            text = EXCLUDED.text,
            "updatedAt" = EXCLUDED."updatedAt",
            deleted = EXCLUDED.deleted,
            "userId" = EXCLUDED."userId",
            "createdAt" = EXCLUDED."createdAt",
            "isCompleted" = EXCLUDED."isCompleted";
    RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;

CREATE TRIGGER trigger_insert_todos
    AFTER INSERT ON todos
    FOR EACH ROW
    EXECUTE PROCEDURE calculate_winning_revision ()

इतना ही! अब हम विजेता संस्करणों को सर्वर और क्लाइंट दोनों पर क्वेरी कर सकते हैं।

कस्टम विरोध समाधान

अब आइए हसुरा और आरएक्सडीबी के साथ कस्टम संघर्ष समाधान को लागू करने पर एक नजर डालते हैं।

सर्वर साइड पर कस्टम विरोध समाधान

मान लें कि हम टोडो को फ़ील्ड द्वारा मर्ज करना चाहते हैं। हम ऐसा करने के बारे में कैसे जाते हैं? नीचे दिया गया सार हमें यह दिखाता है:

वह एसक्यूएल बहुत कुछ दिखता है लेकिन वास्तविक विलय रणनीति से संबंधित एकमात्र हिस्सा यह है:

CREATE OR REPLACE FUNCTION merge_revisions (item1 jsonb, item2 jsonb)
    RETURNS jsonb
    AS $$
BEGIN
    IF NOT item1 ? 'id' THEN
        RETURN item2;
    ELSE
        RETURN item1 || (item2 -> 'diff');
    END IF;
END;
$$
LANGUAGE plpgsql;

CREATE OR REPLACE AGGREGATE agg_merge_revisions (jsonb) (
    INITCOND = '{}',
    STYPE = jsonb,
    SFUNC = merge_revisions
);

यहां हम एक कस्टम पोस्टग्रेज एग्रीगेट फ़ंक्शन की घोषणा करते हैं agg_merge_revisions तत्वों को मिलाने के लिए। जिस तरह से यह काम करता है वह एक 'कम करें' फ़ंक्शन के समान है:पोस्टग्रेज कुल मान को '{}' में प्रारंभ करेगा , फिर merge_revisionsचलाएँ वर्तमान समुच्चय और विलय के लिए अगले तत्व के साथ कार्य करें। तो अगर हमारे पास विलय करने के लिए 3 विरोधाभासी संस्करण थे तो परिणाम होगा:

merge_revisions(merge_revisions(merge_revisions('{}', v1), v2), v3)

अगर हम दूसरी रणनीति लागू करना चाहते हैं तो हमें merge_revisions . को बदलना होगा समारोह। उदाहरण के लिए, यदि हम 'अंतिम लेखन जीत' रणनीति को लागू करना चाहते हैं:

CREATE OR REPLACE FUNCTION merge_revisions (item1 jsonb, item2 jsonb)
    RETURNS jsonb
    AS $$
BEGIN
    IF NOT (item1 ? 'id') THEN
        RETURN item2;
    ELSE
        IF (item2 -> 'updatedAt') > (item1 -> 'updatedAt') THEN
            RETURN item2
        ELSE
            RETURN item1
        END IF;
    END IF;
END;
$$
LANGUAGE plpgsql;

उपरोक्त सार में सम्मिलित क्वेरी को पोस्ट इंसर्ट ट्रिगर में चलाया जा सकता है ताकि जब भी विरोध हो, ऑटो-मर्ज हो सके।

नोट: ऊपर हमने कस्टम संघर्ष समाधान को लागू करने के लिए SQL का उपयोग किया है। एक वैकल्पिक तरीका यह है कि एक क्रिया लिखें:

  1. डिफॉल्ट ऑटो-जेनरेटेड इंसर्ट म्यूटेशन के बजाय इंसर्ट को हैंडल करने के लिए एक कस्टम म्यूटेशन बनाएं।
  2. एक्शन हैंडलर में रिकॉर्ड का नया संशोधन बनाएं। हम इसके लिए हसुरा इंसर्ट म्यूटेशन का उपयोग कर सकते हैं।
  3. सूची क्वेरी का उपयोग करके वस्तु के लिए सभी संशोधन प्राप्त करें
  4. संशोधन ट्री को पार करके किसी भी विरोध का पता लगाएं।
  5. मर्ज किए गए संस्करण को वापस लिखें।

यदि आप इस तर्क को SQL के अलावा किसी अन्य भाषा में लिखना पसंद करते हैं तो यह दृष्टिकोण आपको पसंद आएगा। एक और तरीका यह है कि परस्पर विरोधी संशोधन दिखाने के लिए एक SQL दृश्य बनाया जाए और शेष तर्क को क्रिया हैंडलर में लागू किया जाए। यह ऊपर चरण 4 को सरल बना देगा क्योंकि अब हम केवल विरोधों का पता लगाने के लिए दृश्य को क्वेरी कर सकते हैं।

क्लाइंट पक्ष पर कस्टम विरोध समाधान

ऐसे परिदृश्य हैं जहां आपको किसी विरोध को हल करने में सक्षम होने के लिए उपयोगकर्ता के हस्तक्षेप की आवश्यकता होती है। उदाहरण के लिए, यदि हम ट्रेलो ऐप की तरह कुछ बना रहे थे और दो उपयोगकर्ताओं ने एक ही कार्य के विवरण को संशोधित किया, तो हो सकता है कि आप उपयोगकर्ता को दोनों संस्करण दिखाना चाहें और उन्हें मर्ज किए गए संस्करण बनाने दें। इन परिदृश्यों में हमें क्लाइंट-साइड पर संघर्ष को हल करने की आवश्यकता होगी।

क्लाइंट-साइड संघर्ष समाधान को लागू करना आसान है क्योंकि PouchDB पहले से ही परस्पर विरोधी संशोधनों को क्वेरी करने के लिए API को उजागर करता है। अगर हम todos . को देखें तो पिछली पोस्ट से RxDB संग्रह, यहां बताया गया है कि हम परस्पर विरोधी संस्करण कैसे प्राप्त कर सकते हैं:

todos.pouch.get(todo.id, {
    conflicts: true
})

उपरोक्त क्वेरी _conflicts . में परस्पर विरोधी संशोधनों को भर देगी परिणाम में क्षेत्र। फिर हम इन्हें समाधान के लिए उपयोगकर्ता के सामने प्रस्तुत कर सकते हैं।

निष्कर्ष

PouchDB वर्जनिंग और संघर्ष प्रबंधन समाधान के लिए एक लचीला और शक्तिशाली निर्माण के साथ आता है। इस पोस्ट ने हमें दिखाया कि हसुरा/पोस्टग्रेस के साथ इन निर्माणों का उपयोग कैसे करें। इस पोस्ट में हमने plpgsql का उपयोग करके ऐसा करने पर ध्यान केंद्रित किया है। हम एक अनुवर्ती पोस्ट करेंगे जिसमें दिखाया जाएगा कि इसे क्रियाओं के साथ कैसे किया जाए ताकि आप बैकएंड पर अपनी पसंद की भाषा का उपयोग कर सकें!

इस लेख का आनंद लिया? हसुरा और ग्राफक्यूएल पर अधिक चर्चा के लिए डिस्कॉर्ड पर हमसे जुड़ें!

यह जानने के लिए कि हम नए लेख कब प्रकाशित करते हैं, हमारे न्यूज़लेटर के लिए साइन अप करें।


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Ubuntu 20.04 में Apache CouchDB कैसे स्थापित करें?

  2. क्या किसी ने कॉच डीबी, और विभिन्न ऑफ़लाइन कार्यान्वयन (पाउच डीबी) की कोशिश की है?

  3. काउचबेस डीबीए के लिए उपयोगी स्क्रिप्ट

  4. लिनक्स में Apache CouchDB 2.3.0 कैसे स्थापित करें?

  5. CentOS 8 . पर Apache CouchDB स्थापित करना