如何在 FaunaDB 中获取嵌套文档?

How to get nested documents in FaunaDB?

要在 Fauna 中获取单个文档,我们会这样做:

q.Get(q.Ref(q.Collection('posts'), '192903209792046592'))

我们得到类似的东西:

{
  data: {
    title: 'Lorem ipsum',
    authorId: '892943607792046595'
  }
}

是否可以在同一查询中获取 post 和作者?

像这样:

{
  data: {
    title: 'Lorem ipsum',
    author: {
      name: 'John Doe'
    }
  }
}

所以首先,最好在文档中存储 refs 而不是 ids。

在问题中存储示例 post 时,它应该是这样的(使用 JS 驱动程序):

{
  title: 'Lorem ipsum',
  authorRef: q.Ref(q.Collection("authors"), "1234556456858234")
}

然后要获得带有嵌套作者的 post,您需要使用 Let.

创建自定义对象

它会是这样的(再次使用 JS 驱动程序):

q.Let(
  {
    postDoc: q.Get(q.Ref(Collection('posts'), '192903209792046592')),
    authorRef: q.Select(['data', 'authorRef'], q.Var('postDoc')),
    authorDoc: q.Get(q.Var('authorRef')),
  },
  {
    title: q.Select(['data', 'title'], q.Var('postDoc')),
    author: {
      name: q.Select(['data', 'name'], q.Var('authorDoc')), 
    }
  }
)

哪个 return:

{
  title: 'Lorem ipsum',
  author: {
    name: 'John Doe'
  }
}

另一种选择可能是 return 并排放置两个完整文档:

q.Let(
  {
    postDoc: q.Get(q.Ref(Collection('posts'), '192903209792046592')),
    authorRef: q.Select(['data', 'authorRef'], q.Var('postDoc'))
  },
  {
    postDoc: q.Var('postDoc'),
    authorDoc: q.Get(q.Var('authorRef')),
  }
)

由于这是一个常见问题,我将对其进行扩展并为您提供入门所需的所有信息。我最近写了一个例子,很快也会详细说明这一点。

我将逐步构建查询以尽可能地受教育 比方说..我们写了一个类似推特的应用程序并想要检索推文。 我们要做的第一件事就是获取推文列表。

首先..获取参考资料

Paginate(Documents(Collection('fweets')))

其中 return 是参考列表

...或索引值

Paginate(Documents(Index('some_index')))

其中 return 是您在创建索引时选择的所有值,例如:[[value1, value2], ...]

这将 return 一页参考文献,或者本质上是一个参考文献列表。

使用 Get

获取列表的实际文档

然后你做你在你的问题中所做的,你 Get 通过用 Map 映射它的引用(并且 Map 将是随着我们的进一步发展,您的主力将回答您的问题)

Map(
   Paginate(Documents(Collection('fweets'))),
   Lambda('ref', Var('ref'))
)

转换这些文档以获得其他数据(您的具体问题)

您可以使用与我们获取参考完全相同的技术,在文档上映射。只有现在我们才会对指向其他集合的引用执行 Get。想象一下,我的每个 Tweets 中都有一个 Author,让我们找到那个作者。我们将使用 Let 来构造我们的查询并逐步进行 让我们首先用 Let

重构我们的查询
Map(
  Paginate(Documents(Collection('fweets'))),
  // and in this function, the magic will happen, for now we just return the tweet.
  Lambda('f',
    Let({
        fweet: Get(Var('f'))
      },
      Var('fweet')
    )
  )
)

我们现在将添加一行以获取作者。

Map(
  Paginate(Documents(Collection('fweets'))),
  // and in this function, the magic will happen
  Lambda('f',
    Let({
        fweet: Get(Var('f')),
        author: Get(Select(['data', 'author'], Var('fweet'))), // we get the author reference
      },
      // And now we return a nested doc
      {
        fweet: Var('fweet'),
        author: Var('author')
      }
    )
  )
)

这会 return:

[{
   "fweet": {
      < your tweet data > 
    },
    "author": {
      < your author data >
    }
}, ... ]

既然我们有了这个结构,添加一些额外的东西就很容易了。想象一下,我们还有一条 'asset' 推文链接到我们将其 ref 存储在推文中的推文

Map(
  Paginate(Documents(Collection('fweets'))),
  Lambda('f',
    Let({
        fweet: Get(Var('f')),
        author: Get(Select(['data', 'author'], Var('fweet'))), 
        asset: Get(Select(['data', 'asset'], Var('fweet')))
      },
      // And now we return a nested doc
      {
        fweet: Var('fweet'),
        author: Var('author'),
        asset: Var('asset'),
      }
    )
  )
)

当然..如果我们想要获取的东西不是存储的引用但我们想加入属性怎么办?那么想象一下,我们想要获取一条推文上的多条评论?这就是索引的用武之地!

Map(
  Paginate(Documents(Collection('fweets'))),
  Lambda('f',
    Let({
        fweet: Get(Var('f')),
        author: Get(Select(['data', 'author'], Var('fweet'))), 
        asset: Get(Select(['data', 'asset'], Var('fweet'))), 
        comments: Map(
           Paginate(Match(Index('comments_by_fweet_ordered'), Var('f'))),
           Lambda(
              // my index has two values, I only need the comment reference but adding the ts makes them appear in order!
              ['ts', 'commentref'], 
              Get(Var('commentref'))
           )
        )
      },
      // And now we return a nested doc
      {
        fweet: Var('fweet'),
        author: Var('author'),
        asset: Var('asset'),
        comments: Var('comments')
      }
    )
  )
)

就像那样......您可以逐渐增加复杂性并进行非常复杂的查询。我的应用程序中的查询会像这样继续进行,以获取诸如推文统计信息之类的信息,如果是转推,甚至是原始推文 在 FQL 中实际上几乎没有什么不能做的:)