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

时间:2020-04-08 15:58:48

标签: faunadb

要在动物区系中获取单个文档,我们要做:

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

我们得到类似的东西:

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

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

类似这样的东西:

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

2 个答案:

答案 0 :(得分:7)

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

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

首先。获取参考

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

返回引用列表

...或索引值

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

返回创建索引时选择的所有值,例如:[[value1,value2],...]

这将返回引用页面,或本质上是引用列表。

使用Get获取列表的实际文档

然后,您按照问题的方式去做,就可以通过 Map 在地图上进行映射来获取(而Map将是您回答问题的主要动力。进一步)

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

转换这些文档以获取其他数据(您的特定问题)

您可以使用与获取参考文献,在文档上进行映射完全相同的技术。只有现在,我们才对指向其他集合的引用执行Get操作。想象一下,我的每个推文中都有一个 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')
      }
    )
  )
)

这将返回:

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

现在我们有了这个结构,添加一些额外的东西很容易。想象一下,我们还有一个与该推文链接的“资产”推文,我们将其引用存储在推文中

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')
      }
    )
  )
)

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

答案 1 :(得分:3)

因此,首先,最好将引用存储在文档中,而不是id中。

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

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

然后使用嵌套的作者来发帖,您需要使用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')), 
    }
  }
)

哪个会返回:

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

另一种选择是简单地并排返回两个完整文档:

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')),
  }
)