Javascript 如何更新";“对象数组”;和Firestore一起?

Javascript 如何更新";“对象数组”;和Firestore一起?,javascript,arrays,object,firebase,google-cloud-firestore,Javascript,Arrays,Object,Firebase,Google Cloud Firestore,我目前正在尝试Firestore,但我遇到了一个非常简单的问题:“更新数组(也称为子文档)” 我的数据库结构非常简单。例如: proprietary: "John Doe", sharedWith: [ {who: "first@test.com", when:timestamp}, {who: "another@test.com", when:timestamp}, ], 我正在尝试(没有成功)将新记录推送到shareWith对象数组中 我试过: // With SE

我目前正在尝试Firestore,但我遇到了一个非常简单的问题:“更新数组(也称为子文档)”

我的数据库结构非常简单。例如:

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() }] })
都不管用。这些查询覆盖了我的数组


答案可能很简单,但我找不到它…

编辑2018年8月13日:现在在Cloud Firestore中支持本机阵列操作。见下文


目前无法更新Cloud Firestore中的单个数组元素(或添加/删除单个元素)

此代码如下:

firebase.firestore()
.collection('proprietary')
.doc(docID)
.set(
  { sharedWith: [{ who: "third@test.com", when: new Date() }] },
  { merge: true }
)
这意味着将文档设置为
propertial/docID
,以便
sharedWith=[{who:third@test.com“,when:new Date()}
但不影响任何现有的文档属性。这与您提供的
update()
调用非常相似,但是
set()
调用创建文档(如果文档不存在),而
更新()调用将失败

所以你有两个选择来实现你想要的

选项1-设置整个阵列

使用数组的全部内容调用
set()

选项2-使用子集合

您可以将
与主文档的子集合
共享。然后
添加单个项目将如下所示:

firebase.firestore()
  .collection('proprietary')
  .doc(docID)
  .collection('sharedWith')
  .add({ who: "third@test.com", when: new Date() })
proprietary: "John Doe"
sharedWith:{
  whoEmail1: {when: timestamp},
  whoEmail2: {when: timestamp}
}
当然,这会带来新的限制。您将无法查询 基于共享对象的文档,您也无法
在一次操作中获取文档和所有与
数据共享的

除了上面提到的答案。这样就可以了。 使用Angular 5和AngularFire2。或使用firebase.firestore()而不是this.afs

  // 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
    });
 }  
您可以使用事务()获取数组,推送它,然后更新文档:

    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);
    });
在此基础上,还有一个第三选项,它让我的事情变得更简单,那就是使用谷歌所谓的地图,它本质上是一本字典

我认为字典更适合您所描述的用例。我通常使用数组来处理实际上没有太多更新的内容,因此它们或多或少都是静态的。但是对于需要大量编写的内容,特别是需要为链接到数据库中其他内容的字段更新的值,字典被证明是非常有用的易于维护和使用

因此,对于您的特定情况,DB结构如下所示:

firebase.firestore()
  .collection('proprietary')
  .doc(docID)
  .collection('sharedWith')
  .add({ who: "third@test.com", when: new Date() })
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+'。当在set方法中直接使用“
时,至少在Node.js云函数中使用它时,会导致错误。

将John Doe视为文档而不是集合

给它一个与其他人共享的东西的集合

然后,您可以映射并查询John Doe与其他人共享的并行things集合中的共享内容

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

Firestore现在有两个函数,允许您在不重新写入整个内容的情况下更新数组

链接:,特别是

更新数组中的元素

如果文档包含数组字段,则可以使用arrayUnion()和 arrayRemove()用于添加和删除元素。arrayUnion()用于添加元素 指向数组,但仅指向尚未存在的元素。arrayRemove() 删除每个给定元素的所有实例


很抱歉,派对迟到了,但Firestore早在2018年8月就解决了这个问题,所以如果您还在这里寻找,那么所有关于阵列的问题都已经解决了


array包含、arrayRemove、arrayUnion,用于检查、删除和更新阵列。希望对您有所帮助。

如果有人正在寻找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));
List List=java.util.Arrays.asList(“A”、“B”);
Object[]fieldsToUpdate=list.toArray();
DocumentReference docRef=getCollection().document(“docId”);
docRef.update(fieldName,FieldValue.arrayUnion(fieldsToUpdate));

要从数组中删除项目,请执行以下操作:
FieldValue.arrayRemove()

以下是Firestore文档中的最新示例:

firebase.firestore.FieldValue

var washingtonRef=db.collection(“cities”).doc(“DC”);
//以原子方式将新区域添加到“区域”数组字段。
washingtonRef.update({
地区:firebase.firestore.FieldValue.arrayUnion(“弗吉尼亚州大城市”)
});
//以原子方式从“区域”数组字段中删除区域。
washingtonRef.update({
地区:firebase.firestore.FieldValue.arrayRemove(“东海岸”)
});
addToCart(docId:string,prodId:string):承诺{
返回此.baseAngularFirestore.collection('carts').doc(docId).update({
产品:
firestore.FieldValue.arrayUnion({
productId:prodId,
数量:1
}),
});
}

我们可以使用
arrayUnion({})
方法来实现这一点

试试这个:

collectionRef.doc(ID).更新({
与管理员共享:admin.firestore.FieldValue.arrayUnion({
谁∶first@test.com",
时间:新日期()
})
});

文档可以在此处找到:

如果您想更新firebase文档中的数组。 你可以这样做

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

    documentRef.update({
yourArrayName: firebase.firestore.FieldValue.arrayUnion("The Value you want to enter")});
#编辑(添加说明:)) 假设您有一个数组要更新现有firestore文档字段。您可以使用
set(yourData,{merge:true})
passing setOptions(set函数中的第二个参数)和
{merge:true}
来合并更改,而不是覆盖。以下是官方文档对此的说明

一个选项对象,用于配置DocumentReference、WriteBatch和Tr中set()调用的行为