【问题标题】:How do I implement a getOrCreate within a Firestore transaction?如何在 Firestore 事务中实现 getOrCreate?
【发布时间】:2018-11-01 17:24:13
【问题描述】:

我正在尝试实现报价书签服务。

  • 给定一个报价集合,它有四个信息 - 报价、用户 ID、作者 ID 和 sourceId。
  • 给定一个作者集合,它有两个信息 - 名称、用户 ID
  • 给定一个源集合,它包含三个信息 - 名称(星球大战)、类型 (书籍、电影)、用户 ID

当用户尝试保存报价时,我希望有一个交易来检查作者是否存在(通过名称查询。如果是,则返回 authorId。如果不,创建作者)。源+类型也是如此。作者和来源都将返回各自的 ID。在保存报价时,报价对象将使用 authorIdsourceId 创建。

这种情况可能吗?我检查了 Firestore.firestore().transaction 中只有 getDocument 函数,我无法使用 whereField() 进行查询。

我在某处读到过,我们可以通过规则强制执行创建,并在 try/catch 中抛出错误或某种错误,其中 catch 块将执行 getDocument?

如果我无法在事务中进行查询并且只能依赖 getDocument,这是否意味着作者/源集合的 ID 必须是一个复合键,例如“userId + hash(author/source's名字)”?

对执行此类操作有什么建议?还是 Firestore 无法处理这样的用例?

总之,我正在尝试这样做(在伪代码中)...

Firestore.transaction {

  // Get or create author
  let author = Author.getOrCreate("Yoda", userId)

  // Get or create source
  let source = Source.getOrCreate("Star Wars", "film", userId)

  // Save quote
  let quote = Quote.create({
     quote: "Do or do not. There is no try", 
     authorId: author.id, 
     sourceId: source.id, 
     userId: userId
  })

}

【问题讨论】:

    标签: firebase google-cloud-firestore


    【解决方案1】:

    在事务中,所有读取都应该先进行。您可以使用transaction.getAll() 获取作者和来源,如果它们不存在则创建它们:

    const authorsRef = db.collection('authors')
    const sourcesRef = db.collection('sources')
    const quotesRef = db.collection('quotes')
    
    db.runTransaction(transaction => transaction
      .getAll(
        authorsRef.where('name', '==', 'Yoda').get(),
        sourcesRef.where('name', '==', 'Star Wars').where('type', '==', 'film').get()
      )
      .then(([ authorDoc, sourceDoc ]) => {
        let author = authorDoc
        let source = sourceDoc
        
    
        if (!author.exists) {
          author = authorsRef.doc()
          transaction.set(author, { /* add author fields here */ })
        }
    
        if (!source.exists) {
          source = sourcesRef.doc()
          transaction.set(source, { /* add source fields here */ })
        }
    
        transaction.set(quotesRef.doc(), {
          // add other quote fields here
          authorId: author.id,
          sourceId: source.id
        })
      })
    )
    

    【讨论】:

    • 我认为 swift 没有 transaction.getAll()。在这种情况下,我的选择是什么?我只是在 runTransaction 块中运行普通查询吗?
    • 不太熟悉 Swift,但 transaction.getAll() 的工作方式类似于 Javascript 的 Promise.all()。如果你知道 Promise.all() 的 Swift 对应物,也许这会起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    相关资源
    最近更新 更多