Firebase 如何在Firestore事务中实现getOrCreate?

Firebase 如何在Firestore事务中实现getOrCreate?,firebase,google-cloud-firestore,Firebase,Google Cloud Firestore,我正在尝试实现报价书签服务 给定一个quote集合,它有四个信息-quote、userId和authorId 和sourceId 给定一个作者集合,它有两个信息-名称、用户ID 给定一个源集合,它有三个信息-名称(星球大战),类型 (书,电影),用户ID 当用户尝试保存报价时,我希望有一个事务,在该事务中我将检查作者是否存在(通过名称进行查询。如果是,则返回作者ID。如果否,则创建作者)。源+类型也是如此。作者和源都将返回各自的ID。保存报价时,将使用authorId和sourceId创建报

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

  • 给定一个quote集合,它有四个信息-quote、userId和authorId 和sourceId
  • 给定一个作者集合,它有两个信息-名称、用户ID
  • 给定一个源集合,它有三个信息-名称(星球大战),类型 (书,电影),用户ID
当用户尝试保存报价时,我希望有一个事务,在该事务中我将检查作者是否存在(通过名称进行查询。如果是,则返回作者ID。如果否,则创建作者)。源+类型也是如此。作者和源都将返回各自的ID。保存报价时,将使用authorIdsourceId创建报价对象

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

我在某个地方读到过,我们可以通过规则强制执行create,并在try/catch中抛出一个错误或某种排序,其中catch块将执行getDocument

如果我不能在事务中执行查询,并且只能依赖getDocument,这是否意味着作者/源集合的Id必须是一个复合键,如“userId+hash(作者/源名称)”

对执行这样的行动有什么建议?或者Firestore不能处理这样的用例

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


在事务中,所有读取都应该先进行。您可以使用
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没有事务处理.getAll()。在这种情况下,我的选择是什么?我只是在runTransaction块中运行普通查询吗?我对Swift不是很熟悉,但是
transaction.getAll()
的工作原理与Javascript的
Promise.all()
类似。如果您知道Promise.all()的Swift对应项,那么这可能会奏效。
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
    })
  })
)