如何更新单个 Firebase Firestore 文档

Posted

技术标签:

【中文标题】如何更新单个 Firebase Firestore 文档【英文标题】:How to update a single firebase firestore document 【发布时间】:2018-09-15 20:44:36 【问题描述】:

身份验证后,我尝试在 /users/ 中查找用户文档,然后我想使用来自 auth 对象的数据以及一些自定义用户属性来更新文档。但是我收到更新方法不存在的错误。有没有办法更新单个文档?所有 firestore 文档示例都假定您拥有实际的文档 ID,并且它们没有任何使用 where 子句查询的示例。

firebase.firestore().collection("users").where("uid", "==", payload.uid)
  .get()
  .then(function(querySnapshot) 
      querySnapshot.forEach(function(doc) 
          console.log(doc.id, " => ", doc.data());
          doc.update(foo: "bar")
      );
 )

【问题讨论】:

为什么不使用uid作为存储数据的实际文档ID呢?这让这个问题变得简单多了。 这真是个好主意。这就是解决方案。由于典型应用程序数据库中的所有内容都将具有与特定用户相关的内容,这在许多关系数据库设计中很常见。我会为 firebase/firestore 推荐一个文档或教程。创建一个单独的 /users 集合并使其与 firebase Auth 用户保持同步并不是那么直观。 我认为这里接受的答案是:***.com/questions/55714423/… 是你要找的 【参考方案1】:

您可以精确地执行以下操作(https://firebase.google.com/docs/reference/js/v8/firebase.firestore.DocumentReference):

var db = firebase.firestore();

db.collection("users").doc(doc.id).update(foo: "bar");

【讨论】:

如果您已经有了 uid,为什么还需要执行 get 请求?我们不是只需要那一行` db.collection("users").doc(doc.id).update(foo: "bar");` db.collection("users").doc(doc.id).update(foo: "bar") 是否同时算作读取和写入?在上面的示例中,仅使用doc.ref.update(foo: "bar") 会更划算吗? 我们需要一个获取请求,因为uid != doc.id。例如,您可能使用了自动分配的文档 ID。 @themanatuf 、 db.collection("users").doc(doc.id).update(foo: "bar")doc.ref.update(foo: "bar") 都应该算作一次写入。不过,您说得对,doc.ref 更好。更新答案,谢谢! 我们如何在文档上使用 where 条件然后更新文档字段?请分享任何建议。谢谢。【参考方案2】:

检查用户是否已经在那里,然后简单地.update,如果没有则.set

    var docRef = firebase.firestore().collection("users").doc(firebase.auth().currentUser.uid);
    var o = ;
    docRef.get().then(function(thisDoc) 
        if (thisDoc.exists) 
            //user is already there, write only last login
            o.lastLoginDate = Date.now();
            docRef.update(o);
        
        else 
            //new user
            o.displayName = firebase.auth().currentUser.displayName;
            o.accountCreatedDate = Date.now();
            o.lastLoginDate = Date.now();
            // Send it
            docRef.set(o);
        
        toast("Welcome " + firebase.auth().currentUser.displayName);
    );
).catch(function(error) 
    toast(error.message);
);

【讨论】:

没有理由做所有这些,因为如果记录不存在 set 将自动更新:firebase.google.com/docs/firestore/manage-data/add-data "如果文档不存在,它将被创建。如果文档存在,其内容将被新提供的数据覆盖,除非您指定数据应合并到现有文档中,如下所示:" 那是 .set 方法。除非有更改,否则如果文档不存在,.update 将失败(与实时数据库不同,如果文档不存在,.update 将为您创建它。 如果文档不存在,今天更新还会失败吗?【参考方案3】:

在您的原始代码中更改此行

doc.update(foo: "bar")

到这里

doc.ref.update(foo: "bar")

应该工作

但更好的方法是使用批量写入: https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes

【讨论】:

【参考方案4】:

你只需要找到文档的官方ID,代码在这里!

    enter code here
    //Get user mail (logined)
    val db = FirebaseFirestore.getInstance()
    val user = Firebase.auth.currentUser
    val mail = user?.email.toString()

       //do update
       val update = db.collection("spending").addSnapshotListener  snapshot, e ->
                val doc = snapshot?.documents
                doc?.forEach 
                    //Assign data that I got from document (I neet to declare dataclass) 
                    val spendData= it.toObject(SpendDt::class.java)
                    if (spendData?.mail == mail) 
                        //Get document ID
                        val userId = it.id
                        //Select collection
                        val sfDocRef = db.collection("spendDocument").document(userId)
                        //Do transaction
                        db.runTransaction  transaction ->
                            val despesaConsum = hashMapOf(
                                "medalHalfYear" to true,
                            )
                            //SetOption.merege() is for an existing document
                            transaction.set(sfDocRef, despesaConsum, SetOptions.merge())
                        
                    

                
            

data class SpendDt(
    var oilMoney: Map<String, Double> = mapOf(),
    var mail: String = "",
    var medalHalfYear: Boolean = false
)

【讨论】:

【参考方案5】:

这样做的正确方法如下; 要在快照对象中进行任何数据操作,我们必须引用 .ref 属性

 firebase.firestore().collection("users").where("uid", "==", payload.uid)
  .get()
  .then(function(querySnapshot) 
      querySnapshot.forEach(function(doc) 
          console.log(doc.id, " => ", doc.data());
          doc.ref.update(foo: "bar")//not doc.update(foo: "bar")
      );
 )

【讨论】:

【参考方案6】:

-- FIREBASE V9 更新--

在较新版本的 Firebase 中,这样做是这样的:

import  doc, updateDoc  from "firebase/firestore";

const washingtonRef = doc(db, "cities", "DC");

// Set the "capital" field of the city 'DC'
await updateDoc(washingtonRef, 
  capital: true
);

【讨论】:

以上是关于如何更新单个 Firebase Firestore 文档的主要内容,如果未能解决你的问题,请参考以下文章

如何将来自不同组件的 firebase auth 和 Cloud Firestore 用作单个 Firebase 应用程序

如何从Swift中的Cloud FireStore Firebase访问特定字段

如何在 Firestore Objective-c 上设置/更新数据时以秒为单位获取 Firebase 服务器时间?

如何使用flutter更新firestore中所有文档的单个字段?

Android Firebase FireStore实时更新分页

从 foreach 中删除单个图像(Firebase 存储)