Firestore로 "객체 배열"을 업데이트하는 방법은 무엇입니까?


104

저는 현재 Firestore를 시도하고 있는데 "배열 업데이트 (하위 문서라고도 함)"라는 매우 간단한 작업에 갇혀 있습니다.

내 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

2018 년 8 월 13 일 수정 : 이제 Cloud Firestore에서 기본 배열 작업이 지원됩니다. 아래 Doug의 답변을 참조하십시오 .


현재는 Cloud Firestore에서 단일 배열 요소를 업데이트 (또는 단일 요소 추가 / 제거) 할 수있는 방법이 없습니다.

이 코드는 다음과 같습니다.

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()하는 동안 문서가 존재하지 않으면 create the 문서를 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

52
이것은 큰 결점이며 Google은 최대한 빨리 수정해야합니다.
Sajith Mantharath

3
@DougGalante의 대답은 이것이 수정되었음을 나타냅니다. arrayUnion방법을 사용하십시오 .
quicklikerabbit

152

Firestore에는 이제 전체 내용을 다시 작성하지 않고도 어레이를 업데이트 할 수있는 두 가지 기능이 있습니다.

링크 : https://firebase.google.com/docs/firestore/manage-data/add-data , 특히 https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array

배열의 요소 업데이트

문서에 배열 필드가 포함 된 경우 arrayUnion () 및 arrayRemove ()를 사용하여 요소를 추가 및 제거 할 수 있습니다. arrayUnion ()은 배열에 요소를 추가하지만 아직 존재하지 않는 요소 만 추가합니다. arrayRemove ()는 주어진 각 요소의 모든 인스턴스를 제거합니다.


57
배열에서 특정 인덱스를 업데이트하는 방법이 있습니까?
아르투르 카르발류

1
"react-native-firebase"와 함께이 어레이 업데이트 기능을 사용하는 방법은 무엇입니까? (나는 react-native-
firebase

4
@ArturCarvalho 아니,이 비디오에서 설명하는 이유 youtube.com/...
아담

3
클라이언트에서이 작업을 수행해야하는 사람은 "import * as firebase from 'firebase / app';" 그런 다음 "firebase.firestore.FieldValue.arrayUnion (NEW_ELEMENT)"
michelepatrassi

1
특정 ID로 배열의 항목을 업데이트하는 방법이 있다면 훌륭합니다. arrayUnion과 같지만 merge : true. 현재 배열 항목을 제거한 다음 새 데이터로 다시 추가하려면 두 번의 작업이 필요합니다.
MadMac

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
당신이 없기 때문에 if 문에서 당신이로 변경해야합니다 documentReference추가를 userRef같이 : transaction.set(userRef, { bookings: [booking] });
Ilir Hushi

8

다음은 Firestore 문서의 최신 예입니다.

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, 이것은 실제로 기존 배열 "regions"에 새로운 문자열 요소 "greater_virginia"를 추가합니다. 나는 그것을 성공적으로 테스트했으며 확실히 "개체"를 추가하지 않았습니다. "push new records"라는 질문과 일치합니다.
Veeresh Devireddy


3

Sam Stern의 답변 을 구축 하기 위해 나를 위해 일을 더 쉽게 만들어 주는 세 번째 옵션 도 있으며 Google에서 기본적으로 사전 인 Map을 사용합니다.

설명하는 사용 사례에 대해 사전이 훨씬 더 좋다고 생각합니다. 나는 일반적으로 너무 많이 업데이트되지 않은 항목에 배열을 사용하므로 다소 정적입니다. 그러나 많이 작성되는 항목, 특히 데이터베이스의 다른 항목에 연결된 필드에 대해 업데이트해야하는 값의 경우 사전이 유지 관리 및 작업이 훨씬 더 쉽다는 것이 입증되었습니다.

따라서 특정 경우의 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'는 set 메서드에서 직접 사용하면 적어도 Node.js 클라우드 함수에서 사용할 때 오류가 발생하기 때문입니다.


2

위에서 언급 한 답변 외에. 이것은 할 것입니다. Angular 5 및 AngularFire2 사용. 또는 this.afs 대신 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

John Doe를 컬렉션이 아닌 문서로 간주

사물과 사물의 컬렉션을 제공합니다.

그런 다음 병렬 thingsSharedWithOthers 컬렉션에서 John Doe의 공유 항목을 매핑하고 쿼리 할 수 ​​있습니다.

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

아무도 배열 필드에 항목을 추가하기 위해 Java 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()


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.