Firestore ile bir “nesne dizisi” nasıl güncellenir?


114

Şu anda Firestore'u deniyorum ve çok basit bir şeye sıkışıp kaldım: "bir diziyi güncelleme (aka bir alt belge)".

DB yapım süper basit. Örneğin:

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

Yeni kayıtları shareWithnesneler dizisine aktarmaya çalışıyorum (başarılı olamıyorum) .

Denedim:

// 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() }] })

Hiçbiri çalışmıyor. Bu sorgular dizimin üzerine yazıyor.

Cevap basit olabilir ama bulamadım ...


Hey anladın mı? Hâlâ bir cevap bulamıyorum.
Yash Jain

Yanıtlar:


78

Düzenleme 13.08.2018 : Artık Cloud Firestore'da yerel dizi işlemleri desteği var. Bkz Doug cevabı aşağıda.


Şu anda Cloud Firestore'da tek bir dizi öğesini güncellemenin (veya tek bir öğe eklemenin / kaldırmanın) bir yolu yoktur.

Bu kod burada:

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

Bu, belgeyi proprietary/docIDöyle ayarlamanızı sharedWith = [{ who: "third@test.com", when: new Date() }ancak mevcut belge özelliklerini etkilememesini söyler . Sağladığınız update()aramaya çok benzer, ancak arama başarısız set()olurken yoksa belgeyi içeren arama belgeyi oluşturur update().

Yani istediğinizi elde etmek için iki seçeneğiniz var.

Seçenek 1 - Tüm diziyi ayarlayın

set()İlk olarak DB'den mevcut verilerin okunmasını gerektiren dizinin tüm içeriği ile çağırın . Eşzamanlı güncellemelerden endişe ediyorsanız, tüm bunları bir işlemde yapabilirsiniz.

Seçenek 2 - Bir koleksiyon kullanın

sharedWithAna belgenin bir koleksiyonunu yapabilirsiniz . Ardından tek bir öğe eklemek şu şekilde görünür:

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

Elbette bu yeni sınırlamalarla birlikte geliyor. Dokümanları kiminle paylaşıldığına göre sorgulayamayacak, dokümanı ve tüm sharedWithverileri tek bir işlemde alamayacaksınız .


9
Bu çok sinir bozucu ... ama delirmediğimi bildirdiğiniz için teşekkürler.
ItJustWerks

53
bu büyük bir dezavantaj, Google'ın en kısa zamanda düzeltmesi gerekiyor.
Sajith Mantharath

3
@ DougGalante'nin cevabı bunun düzeltildiğini gösteriyor. arrayUnionYöntemi kullanın .
quicklikerabbit

158

Firestore'un artık her şeyi yeniden yazmadan bir diziyi güncellemenizi sağlayan iki işlevi var.

Bağlantı: https://firebase.google.com/docs/firestore/manage-data/add-data , özellikle https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array

Bir dizideki öğeleri güncelleme

Belgeniz bir dizi alanı içeriyorsa, öğe eklemek ve kaldırmak için arrayUnion () ve arrayRemove () kullanabilirsiniz. arrayUnion (), bir diziye öğeler ekler, ancak yalnızca önceden mevcut olmayan öğeler. arrayRemove (), verilen her bir öğenin tüm örneklerini kaldırır.


63
Diziden belirli bir dizini güncellemenin herhangi bir yolu var mı?
Artur Carvalho

1
Bu dizi güncelleme özelliği "react-native-firebase" ile nasıl kullanılır? (Bunu react-native-firebase'in resmi belgelerinde bulamıyorum)
kernelman

5
@ArturCarvalho Hayır, bu videoda açıklanmasının nedeni youtube.com/…
Adam

3
istemcide bunu yapması gerekenler için "firebase / app'den firebase olarak içe aktar * seçeneğini kullanın"; ardından "firebase.firestore.FieldValue.arrayUnion (NEW_ELEMENT)"
michelepatrassi

2
Bir dizideki bir öğeyi belirli bir kimliğe sahip güncellemenin bir yolu varsa harika olur. ArrayUnion gibi ama birleştirme ile: true. Şu anda dizi öğesini kaldırmak ve ardından yeni verilerle tekrar eklemek için 2 işlem gerekir.
MadMac

16

Diziyi almak için bir işlem ( https://firebase.google.com/docs/firestore/manage-data/transactions ) kullanabilir, ona aktarabilir ve ardından belgeyi güncelleyebilirsiniz:

    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
Eğer eksik olduğu takdirde açıklamada azından, bu içine değişmelidir documentReferenceeklenti userRefgösterildiği gibi: transaction.set(userRef, { bookings: [booking] });
İlir Hushi

15

Firestore belgelerindeki en son örnek:

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

1
@nifCody, bu gerçekten var olan bir "bölgeler" dizisine yeni bir "daha fazla_virginia" dize öğesi ekleyecektir. Başarıyla test ettim ve kesinlikle "nesne" eklemedim. Belirtildiği gibi şu soruyla uyumludur: "yeni kayıtları aktar".
Veeresh Devireddy


4

Sam Stern'in cevabının üzerine inşa etmek için , işleri benim için kolaylaştıran ve Google'ın Harita olarak adlandırdığı, esasen bir sözlük olan 3. bir seçenek daha var.

Açıkladığın kullanım senaryosu için bir sözlüğün çok daha iyi olduğunu düşünüyorum. Genellikle çok fazla güncellenmeyen şeyler için diziler kullanırım, bu yüzden az ya da çok statiktirler. Ancak çok fazla yazılan şeyler için, özellikle veritabanındaki başka bir şeyle bağlantılı alanlar için güncellenmesi gereken değerler için, sözlüklerin bakımı ve üzerinde çalışmanın çok daha kolay olduğu kanıtlanmıştır.

Yani sizin özel durumunuz için, DB yapısı şöyle görünecektir:

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

Bu, aşağıdakileri yapmanıza izin verecektir:

var whoEmail = 'first@test.com';

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

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

Nesneyi bir değişken olarak tanımlamanın nedeni, 'sharedWith.' + whoEmail + '.when'doğrudan set yönteminin kullanılmasının, en azından bir Node.js bulut işlevinde kullanıldığında, bir hataya neden olmasıdır.


2

Yukarıda belirtilen cevaplar dışında. Bu yapacak. Angular 5 ve AngularFire2'yi kullanma. veya this.afs yerine firebase.firestore () kullanın

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

John Doe'yi bir koleksiyondan çok bir belge olarak düşünün

Ona bir şeyler ve şeyler koleksiyonu verin

Ardından, John Doe'nun paylaştığı şeyleri bu paralel thingsSharedWithOthers koleksiyonunda haritalayabilir ve sorgulayabilirsiniz.

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

Dizi alanına öğe eklemek için Java firestore sdk çözümü arayan biri varsa:

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

Dizi kullanıcısından öğeler silmek için: FieldValue.arrayRemove()



0

Firebase belgesindeki bir diziyi güncellemek istiyorsanız. Bunu yapabilirsiniz.

    var documentRef = db.collection("Your collection name").doc("Your doc name")

    documentRef.update({
yourArrayName: firebase.firestore.FieldValue.arrayUnion("The Value you want to enter")});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.