फायरस्टार के साथ "वस्तुओं की एक सरणी" कैसे अपडेट करें?


104

मैं वर्तमान में फायरस्टार की कोशिश कर रहा हूं, और मैं बहुत ही सरल तरीके से फंस गया हूं: "एक सरणी को अपडेट करना (उर्फ एक सबडिमेन्मेंट)"।

मेरा DB संरचना सुपर सरल है। उदाहरण के लिए:

proprietary: "John Doe",
sharedWith:
  [
    {who: "first@test.com", when:timestamp},
    {who: "another@test.com", when:timestamp},
  ],

मैं कोशिश कर रहा हूं (सफलता के बिना) shareWithवस्तुओं के सरणी में नए रिकॉर्ड को आगे बढ़ाने के लिए ।

मैंने कोशिश की:

// With SET
firebase.firestore()
.collection('proprietary')
.doc(docID)
.set(
  { sharedWith: [{ who: "third@test.com", when: new Date() }] },
  { merge: true }
)

// With UPDATE
firebase.firestore()
.collection('proprietary')
.doc(docID)
.update({ sharedWith: [{ who: "third@test.com", when: new Date() }] })

कोई काम नहीं करता। ये क्वेरी मेरे एरे को ओवरराइट करती हैं।

उत्तर सरल हो सकता है, लेकिन मुझे यह नहीं मिला ...

जवाबों:


71

संपादित करें 08/13/2018 : अब क्लाउड फायरस्टार में देशी सरणी संचालन के लिए समर्थन है। देखें डौग जवाब नीचे।


क्लाउड फायरस्टार में वर्तमान में एकल सरणी तत्व को अपडेट करने (या किसी एकल तत्व को जोड़ने / हटाने) का कोई तरीका नहीं है।

यह कोड यहाँ है:

firebase.firestore()
.collection('proprietary')
.doc(docID)
.set(
  { sharedWith: [{ who: "third@test.com", when: new Date() }] },
  { merge: true }
)

यह दस्तावेज़ को proprietary/docIDऐसे सेट करने के लिए कहता है, sharedWith = [{ who: "third@test.com", when: new Date() }लेकिन किसी भी मौजूदा दस्तावेज़ गुणों को प्रभावित नहीं करने के लिए। यह update()आपके द्वारा प्रदान की गई कॉल के समान है, लेकिन set()यदि update()कॉल विफल हो जाती है, तो यह दस्तावेज़ बनाने के साथ कॉल मौजूद नहीं है ।

इसलिए आपके पास दो विकल्प हैं जो आप चाहते हैं।

विकल्प 1 - पूरी सरणी सेट करें

set()सरणी की संपूर्ण सामग्री के साथ कॉल करें , जिसमें पहले DB से वर्तमान डेटा को पढ़ने की आवश्यकता होगी। यदि आप समवर्ती अद्यतनों के बारे में चिंतित हैं, तो आप लेनदेन में यह सब कर सकते हैं।

विकल्प 2 - एक सबकोलेक्शन का उपयोग करें

आप sharedWithमुख्य दस्तावेज़ का एक सबकोलेक्शन कर सकते हैं । तब एक ही आइटम जोड़ना इस तरह दिखेगा:

firebase.firestore()
  .collection('proprietary')
  .doc(docID)
  .collection('sharedWith')
  .add({ who: "third@test.com", when: new Date() })

बेशक यह नई सीमाओं के साथ आता है। आप उन दस्तावेजों के आधार पर क्वेरी नहीं कर पाएंगे जिनके साथ वे साझा किए गए हैं, और न ही आप sharedWithएक ही ऑपरेशन में डॉक्टर और सभी डेटा प्राप्त कर पाएंगे ।


9
यह बहुत निराशाजनक है ... लेकिन मुझे यह बताने के लिए धन्यवाद कि मैं पागल नहीं हूं।
ItJustWerks

50
यह बड़ी कमी है, Google को इसे ठीक करना होगा।
सजथ मंथरथ

3
@ डगग्लेंटे का उत्तर इंगित करता है कि यह तय हो गया है। arrayUnionविधि का प्रयोग करें ।
क्विकलाइरबबिट 21

152

फायरस्टार के अब दो कार्य हैं जो आपको पूरी बात को फिर से लिखने के बिना एक सरणी को अपडेट करने की अनुमति देते हैं।

लिंक: https://firebase.google.com/docs/firestore/manage-data/add-data , विशेष रूप से https://firebase.google.com/docs/firestore/manage-data/add-data#upateate_elements_in_an_array

एरे में तत्वों को अपडेट करें

यदि आपके दस्तावेज़ में एक सरणी फ़ील्ड है, तो आप तत्वों को जोड़ने और हटाने के लिए arrayUnion () और arrayRemove () का उपयोग कर सकते हैं। arrayUnion () एक सरणी में तत्वों को जोड़ता है लेकिन केवल पहले से मौजूद तत्व नहीं है। arrayRemove () प्रत्येक दिए गए तत्व के सभी उदाहरणों को हटा देता है।


56
क्या एरे से किसी विशिष्ट इंडेक्स को अपडेट करने का कोई तरीका है?
आर्टूर कार्वाल्हो

1
"रिएक्शन-देशी-फायरबेस" के साथ इस सरणी अद्यतन सुविधा का उपयोग कैसे करें? (मैं इस प्रतिक्रिया-देशी-
फायरबेस के

4
@ArturCarvalho नहीं, इस वीडियो में क्यों समझाया गया कारण youtube.com/…
एडम

@ArturCarvalho आपको सरणी से एक विशिष्ट सूचकांक अपडेट करने के लिए कोई समाधान मिल गया है?
योगेंद्र पटेल

3
ग्राहक के लिए इसे करने की आवश्यकता किसके लिए है, "फायरबस / ऐप 'से फायरबेस के रूप में" आयात * "का उपयोग करें; उसके बाद "firebase.firestore.FieldValue.arrayUnion (NEW_ELEMENT)"
मिशेलेपात्रसी

15

आप सरणी प्राप्त करने के लिए एक लेनदेन ( https://firebase.google.com/docs/firestore/manage-data/transactions ) का उपयोग कर सकते हैं , उस पर पुश करें और फिर दस्तावेज़ को अपडेट करें:

    const booking = { some: "data" };
    const userRef = this.db.collection("users").doc(userId);

    this.db.runTransaction(transaction => {
        // This code may get re-run multiple times if there are conflicts.
        return transaction.get(userRef).then(doc => {
            if (!doc.data().bookings) {
                transaction.set({
                    bookings: [booking]
                });
            } else {
                const bookings = doc.data().bookings;
                bookings.push(booking);
                transaction.update(userRef, { bookings: bookings });
            }
        });
    }).then(function () {
        console.log("Transaction successfully committed!");
    }).catch(function (error) {
        console.log("Transaction failed: ", error);
    });

1
बयान करता है, तो आप इस में बदलना चाहिए, क्योंकि आप याद कर रहे हैं documentReferenceजोड़ने userRefदिखाया गया है: transaction.set(userRef, { bookings: [booking] });
Ilir Hushi

8

यहां फायरस्टार प्रलेखन से नवीनतम उदाहरण दिया गया है:

firebase.firestore.FieldValue। ArrayUnion

var washingtonRef = db.collection("cities").doc("DC");

// Atomically add a new region to the "regions" array field.
washingtonRef.update({
    regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")
});

// Atomically remove a region from the "regions" array field.
washingtonRef.update({
    regions: firebase.firestore.FieldValue.arrayRemove("east_coast")
});

@nifCody, यह वास्तव में एक मौजूदा सरणी "क्षेत्रों" में एक नया स्ट्रिंग तत्व "अधिक से अधिक_विर्जिनिया" जोड़ देगा। मैंने इसे सफलतापूर्वक परीक्षण किया है, और निश्चित रूप से "ऑब्जेक्ट" नहीं जोड़ रहा है। यह कहा गया है कि सवाल के साथ सिंक में है: "नए रिकॉर्ड धक्का"।
वीरेश देविरेड्डी

7

पार्टी के लिए देर से क्षमा करें, लेकिन फायरस्टार ने अगस्त 2018 में इसे वापस हल कर दिया है, इसलिए यदि आप अभी भी यहां देख रहे हैं तो यह एरेज़ के संबंध में हल किए गए सभी मुद्दे हैं।

https://firebase.googleblog.com/2018/08/better-arrays-in-cloud-firestore.html आधिकारिक ब्लॉग पोस्ट

सरणी-समाहित, arrayRemove, सरणियों की जाँच, हटाने और अद्यतन करने के लिए arrayUnion। आशा करता हूँ की ये काम करेगा।


3

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

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

तो आपके विशिष्ट मामले के लिए, DB संरचना इस तरह दिखाई देगी:

proprietary: "John Doe"
sharedWith:{
  whoEmail1: {when: timestamp},
  whoEmail2: {when: timestamp}
}

यह आपको निम्नलिखित कार्य करने की अनुमति देगा:

var whoEmail = 'first@test.com';

var sharedObject = {};
sharedObject['sharedWith.' + whoEmail + '.when'] = new Date();
sharedObject['merge'] = true;

firebase.firestore()
.collection('proprietary')
.doc(docID)
.update(sharedObject);

ऑब्जेक्ट को एक चर के रूप में परिभाषित करने का कारण यह है कि 'sharedWith.' + whoEmail + '.when'सेट विधि में सीधे उपयोग करने से एक त्रुटि उत्पन्न होगी, कम से कम जब यह Node.js क्लाउड फ़ंक्शन में उपयोग करेगा।


2

ऊपर वर्णित उत्तर के अलावा। यह कर देगा। Angular 5 और AngularFire2 का उपयोग करना। या इस के बजाय firebase.firestore () का उपयोग करें

  // say you have have the following object and 
  // database structure as you mentioned in your post
  data = { who: "third@test.com", when: new Date() };

  ...othercode


  addSharedWith(data) {

    const postDocRef = this.afs.collection('posts').doc('docID');

    postDocRef.subscribe( post => {

      // Grab the existing sharedWith Array
      // If post.sharedWith doesn`t exsit initiated with empty array
      const foo = { 'sharedWith' : post.sharedWith || []};

      // Grab the existing sharedWith Array
      foo['sharedWith'].push(data);

      // pass updated to fireStore
      postsDocRef.update(foo);
      // using .set() will overwrite everything
      // .update will only update existing values, 
      // so we initiated sharedWith with empty array
    });
 }  

1

एक संग्रह के बजाय जॉन डो को एक दस्तावेज पर विचार करें

इसे चीजों और चीजों का संग्रह दें

फिर आप उस समानांतर चीजों में जॉन डो की साझा की गई चीजों को मैप और क्वेरी कर सकते हैं।

proprietary: "John Doe"(a document)

things(collection of John's things documents)

thingsSharedWithOthers(collection of John's things being shared with others):
[thingId]:
    {who: "first@test.com", when:timestamp}
    {who: "another@test.com", when:timestamp}

then set thingsSharedWithOthers

firebase.firestore()
.collection('thingsSharedWithOthers')
.set(
{ [thingId]:{ who: "third@test.com", when: new Date() } },
{ merge: true }
)

0

किसी को भी सरणी क्षेत्र में आइटम जोड़ने के लिए जावा firestore sdk समाधान की तलाश है:

List<String> list = java.util.Arrays.asList("A", "B");
Object[] fieldsToUpdate = list.toArray();
DocumentReference docRef = getCollection().document("docId");
docRef.update(fieldName, FieldValue.arrayUnion(fieldsToUpdate));

सरणी उपयोगकर्ता से आइटम हटाने के लिए: FieldValue.arrayRemove()


0
addToCart(docId: string, prodId: string): Promise<void> {
    return this.baseAngularFirestore.collection('carts').doc(docId).update({
        products:
        firestore.FieldValue.arrayUnion({
            productId: prodId,
            qty: 1
        }),
    });
}

1
कृपया, अपना उत्तर स्पष्ट करें।
जेने व्रानसेनू

दरअसल,
jasie

-1

यह है कि मैं इसे काम करने के लिए कैसे मिला। आशा है कि यह आप सभी की मदद करेगा क्योंकि मैं इसे बेहतर समाधान के रूप में देखता हूं। यहाँ मैं कार्य स्थिति को खुले (क्लोज़ = झूठ) से बंद (क्लोज़ = ट्रू) में बदलना चाहता हूँ, जबकि वस्तु में बाकी सब समान रखते हुए।

closeTask(arrayIndex) {
        let tasks = this.lead.activityTasks;

        const updatedTask = {
          name: tasks[arrayIndex].name,
          start: tasks[arrayIndex].start,
          dueDate:tasks[arrayIndex].dueDate,
          close: true, // This is what I am changing.
        };
        tasks[arrayIndex] = updatedTask;

        const data = {
          activityTasks: tasks
        };

        this.leadService.updateLeadData(data, this.lead.id);
    }

और यहां वह सेवा है जो वास्तव में इसे अपडेट करती है

 public updateLeadData(updateData, leadId) {
    const leadRef: AngularFirestoreDocument<LeadModel> = this.afs.doc(
      `leads/${leadId}`);

return leadRef.update(updateData);
}

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

क्षमा करें, मुझे नीचे उतरना पड़ा क्योंकि इसमें बुरे व्यवहार हैं।
करोलदीपका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.