firebase firestore 在事务中添加新文档-transaction.add 不是函数

Posted

技术标签:

【中文标题】firebase firestore 在事务中添加新文档-transaction.add 不是函数【英文标题】:firebase firestore adding new document inside a transaction - transaction.add is not a function 【发布时间】:2019-09-04 13:02:50 【问题描述】:

我假设可以执行以下操作:

transaction.add(collectionRef,
  uid: userId,
  name: name,
  fsTimestamp: firebase.firestore.Timestamp.now(),
);

但显然不是:

transaction.add 不是函数

以上消息显示在 chrome 控制台内。

我看到我们可以使用事务的set方法来事务性地添加一个新文档。见:https://firebase.google.com/docs/firestore/manage-data/transactions

问题是如果我使用 set 而不是 add(无论如何都不支持),文档的 id 应该由我手动创建,firestore 不会创建它。 见:https://firebase.google.com/docs/firestore/manage-data/add-data

如果没有自动为您生成 id 的 add 方法,您是否发现这样做的任何缺点?

例如,考虑到包括性能在内的各种问题,firestore 本身生成的 id 是否可能以某种方式进行了优化?

在使用 transaction.set 时,您使用哪个库/方法在 react-native 中创建文档 ID?

谢谢

【问题讨论】:

【参考方案1】:

如果您想生成一个唯一 ID 以供以后在事务中创建文档时使用,您所要做的就是使用不带参数的 CollectionReference.doc() 来生成一个 DocumentReference,您可以稍后在事务中设置()。

(您在回答中提出的建议是为了达到同样的效果需要做更多的工作。)

// Create a reference to a document that doesn't exist yet, it has a random id
const newDocRef = db.collection('coll').doc();

// Then, later in a transaction:
transaction.set(newDocRef,  ... );

【讨论】:

db.collectionRef 你的意思是db.collection,对吧? @DougStevenson 嗯,当我尝试这个时,我遇到了一个错误:FirebaseError: Function CollectionReference.doc() 要求它的第一个参数是非空字符串类型,但它是:未定义。有更新吗? 好的,我可以看到,它不适用于 angularfire:/ @DougStevenson:这是否意味着文档 ID 被保留?如果是这样:是否需要在事务中调用 doc()?或者我们是否依赖 id 生成器在另一个不相关的调用中不统计地提供这个值?【参考方案2】:

经过更多挖掘后,我在 firestore 本身的源代码中发现了以下用于 id 生成的类/方法:

export class AutoId 
  static newId(): string 
    // Alphanumeric characters
    const chars =
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let autoId = '';
    for (let i = 0; i < 20; i++) 
      autoId += chars.charAt(Math.floor(Math.random() * chars.length));
    
    assert(autoId.length === 20, 'Invalid auto ID: ' + autoId);
    return autoId;
  

见:https://github.com/firebase/firebase-js-sdk/blob/73a586c92afe3f39a844b2be86086fddb6877bb7/packages/firestore/src/util/misc.ts#L36

我提取了方法(除了 assert 语句)并将其放在我的代码中的方法中。然后我使用了事务的set方法如下:

generateFirestoreId()
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        let autoId = '';
        for (let i = 0; i < 20; i++) 
            autoId += chars.charAt(Math.floor(Math.random() * chars.length));
        
        //assert(autoId.length === 20, 'Invalid auto ID: ' + autoId);
        return autoId;
    

那么,

newDocRef = db.collection("PARENTCOLL").doc(PARENTDOCID).collection('SUBCOLL').doc(this.generateFirestoreId());
                        transaction.set(newDocRef,
                            uid: userId,
                            name: name,
                            fsTimestamp: firebase.firestore.Timestamp.now(),
                        );

由于我使用与 firestore 本身相同的 id 生成算法,我感觉更好。

希望这可以帮助/指导某人。

干杯。

【讨论】:

【参考方案3】:

根据 Doug Stevenson 的回答,这就是我使用 @angular/fire 的方式:

// Create a reference to a document and provide it a random id, e.g. by using uuidv4
const newDocRef = this.db.collection('coll').doc(uuidv4()).ref;

// In the transaction:
transaction.set(newDocRef,  ... );

【讨论】:

【参考方案4】:

完成 Stefan 的回答。对于那些使用 Angularfire 的用户,在 5.2 版之前使用 CollectionReference.doc() 会导致错误“CollectionReference.doc() 要求其第一个参数是非空字符串类型”。

这个解决方法对我有用:

const id = this.afs.createId();
const ref = this.afs.collection(this.collectionRef).doc(id);
transaction.set(ref,  ... );

信用:https://github.com/angular/angularfire/issues/1974#issuecomment-448449448

【讨论】:

【参考方案5】:

我想添加一个解决id 问题的答案。无需生成您自己的ids。 documentReference 在调用 transaction.set() 后更新,因此要访问 Firestore 的 id,您只需执行以下操作:

const docRef = collectionRef.doc();
const result = await transaction.set(docRef, input);
const id = docRef.id;

【讨论】:

以上是关于firebase firestore 在事务中添加新文档-transaction.add 不是函数的主要内容,如果未能解决你的问题,请参考以下文章

Firestore是否提供更多的锁定事务,比如表到表的概念?

Flutter Firebase/Firestore 一次写入多个表

在 pubspec.yaml 文件中添加 firebase_auth 或 cloud_firestore 时构建失败并出现异常(firebase_core 正在工作):

如何在不覆盖的情况下向 Firebase Firestore 添加值?

在添加或删除的 Firebase Firestore 数据中重复 RecyclerView 项

为啥 Firebase 数据库(Firestore)不添加文档