【问题标题】:Firestore how to get last document of collection and add new with incremented id?Firestore如何获取集合的最后一个文档并添加带有增量ID的新文档?
【发布时间】:2019-05-22 15:37:26
【问题描述】:

我的事件集合中的文档的自动生成 ID 可能出错了。我为生成的事件添加了 eventId,并为每个事件手动分配了 eventId。

我能否以某种方式获取带有 eventId 的最后一个文档,并添加新文档,最后一个文档的 eventId 加一。

或者我应该删除自动生成的基于 Id 的事件并使用非自动生成的 id 创建新的事件?

GitHub:https://github.com/Verthon/event-app

我已经在 netlify 上发布了正在运行的 React.js 应用程序:https://eventooo.netlify.com/

它是如何工作的:

  • 我为事件集合内的每个虚拟事件添加了唯一的 eventId,
  • 基于这个唯一的 eventId,我创建了指向特定单个 Event.js 的链接,
  • 用户可以在 /create-event 中创建提供信息的事件,
  • 一旦有人创建了一个事件,我想将事件添加到带有递增 id 的事件集合中,我已经添加了 7 个在控制台内创建的事件,所以接下来应该有 id=7,可能类似于 event1、event2 ...自动递增
  • 在用户集合中,我存储来自用户提供的身份验证和主机名的 currentUser.uid
Event Creator

submitEvent = (e) => {
    e.preventDefault();
    const eventRef = this.props.firebase.db.collection("events").doc();
    eventRef.set({
      title: this.state.title,
      host: this.state.host,
      localization: this.state.localization,
      description: this.state.description,
      category: this.state.category,
      day: this.state.day,
      hour: this.state.hour,
      featuredImage: this.state.imageUrl,
      uid: this.props.firebase.auth.currentUser.uid
    });


    const citiesRef = this.props.firebase.db.collection("cities").where("city", "==", this.state.localization);
    const cityRef = this.props.firebase.db.collection("cities").doc();
    citiesRef.get()
      .then(querySnapshot => {
        if(querySnapshot.exists){
          console.log("exist");
          return
        }else{
          cityRef.set({
            city: this.state.localization,
          })
        }
      });
    const userRef = this.props.firebase.db.collection("users").doc();
    userRef.set({
      user: this.state.host,
      uid: this.props.firebase.auth.currentUser.uid
    });


谢谢

【问题讨论】:

    标签: firebase google-cloud-firestore


    【解决方案1】:

    我了解您希望您的 eventId 值来自数字序列。满足这种需求的最佳方法是使用分布式计数器,如文档中所述:https://firebase.google.com/docs/firestore/solutions/counters

    我不知道您使用的是哪种语言,但我将本文档中三个函数的 JavaScript 代码粘贴到下方,并编写代码生成可用于创建文档的序列号。

      var db = firebase.firestore();
    
      //From the Firebase documentation
    
      function createCounter(ref, num_shards) {
        var batch = db.batch();
    
        // Initialize the counter document
        batch.set(ref, { num_shards: num_shards });
    
        // Initialize each shard with count=0
        for (let i = 0; i < num_shards; i++) {
          let shardRef = ref.collection('shards').doc(i.toString());
          batch.set(shardRef, { count: 0 });
        }
    
        // Commit the write batch
        return batch.commit();
      }
    
      function incrementCounter(db, ref, num_shards) {
        // Select a shard of the counter at random
        const shard_id = Math.floor(Math.random() * num_shards).toString();
        const shard_ref = ref.collection('shards').doc(shard_id);
    
        // Update count
        return shard_ref.update(
          'count',
          firebase.firestore.FieldValue.increment(1)
        );
      }
    
      function getCount(ref) {
        // Sum the count of each shard in the subcollection
        return ref
          .collection('shards')
          .get()
          .then(snapshot => {
            let total_count = 0;
            snapshot.forEach(doc => {
              total_count += doc.data().count;
            });
    
            return total_count;
          });
      }
    
      //Your code
    
      var ref = firebase
        .firestore()
        .collection('counters')
        .doc('1');
    
      var num_shards = 2  //Adapt as required, read the doc
    
      //Initialize the counter bay calling ONCE the createCounter() method
    
      createCounter(ref, num_shards);
    
      //Then, when you want to create a new number and a new doc you do
    
      incrementCounter(db, ref, num_shards)
        .then(() => {
          return getCount(ref);
        })
        .then(count => {
          console.log(count);
          //Here you get the new number form the sequence
          //And you use it to create a doc
          db.collection("events").doc(count.toString()).set({
             category: "education",
             //.... 
          })
        });
    

    如果没有关于功能需求的详细信息,很难说使用序列中的数字作为文档的 uid 还是作为文档中的字段值之间是否存在差异。这取决于您可能对此集合执行的查询。

    【讨论】:

    • 感谢您的回复,我已对帖子进行了一些解释。这对我来说很复杂,因为不幸的是我第一次使用数据库。
    • 我从您的更新中了解到,eventId id 的主要用途是“创建指向特定单个 Event.js 的链接”。所以使用顺序 eventId 作为文档 id 是一个不错的方法。
    • 感谢您的澄清。当用户提交另一个事件时,我仍然不知道如何以编程方式增加 eventId。我是否应该遍历所有事件并以某种方式获取并存储最大的 eventId 只是为了将当前值加 1?很抱歉提出一些琐碎的问题,但我现在完全陷入困境。
    • 您可以循环遍历所有事件,但需要使用事务来执行此操作,并且只有 Node.js API 允许读取事务中的一组文档。客户端 SDK 仅提供读取一个文档的可能性。这就是为什么我的回答提出了一种不同的方法:维护一个计数器,每次创建新文档时都会增加一个计数器。结果是一样的。
    • 仅供参考,您的方法可能遇到的问题是,在用户读取事件集合并写入新文档之间,另一个用户执行相同操作并创建另一个“新”文档,以两个结尾具有相同 userId 的文档。这就是为什么在这种情况下,我们通常在读取集合和创建文档或递增计数器时使用事务 (firebase.google.com/docs/firestore/manage-data/transactions)。
    猜你喜欢
    • 2018-07-22
    • 1970-01-01
    • 2019-09-17
    • 1970-01-01
    • 2019-09-24
    • 2020-12-04
    • 1970-01-01
    • 2021-06-11
    • 1970-01-01
    相关资源
    最近更新 更多