<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Fauna, Inc.</title>
    <description>The latest articles on Forem by Fauna, Inc. (@fauna).</description>
    <link>https://forem.com/fauna</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1138%2Fdba4b734-81c2-404c-b23e-9608ae98ee49.png</url>
      <title>Forem: Fauna, Inc.</title>
      <link>https://forem.com/fauna</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fauna"/>
    <language>en</language>
    <item>
      <title>Simplify serverless scaling and data management with Fauna and Cloudflare Workers</title>
      <dc:creator>Kirk Kirkconnell</dc:creator>
      <pubDate>Wed, 13 Nov 2024 19:07:47 +0000</pubDate>
      <link>https://forem.com/fauna/simplify-scaling-and-data-management-with-fauna-and-cloudflare-workers-lkf</link>
      <guid>https://forem.com/fauna/simplify-scaling-and-data-management-with-fauna-and-cloudflare-workers-lkf</guid>
      <description>&lt;p&gt;In a world where we demand speed, flexibility, and seamless scalability, serverless architecture has emerged as a new gold standard. For many developers, achieving a truly serverless experience—where every element of scaling, replication, and data consistency is managed without additional infrastructure headaches—can still seem elusive. Fauna, in partnership with Cloudflare, has made True Serverless possible. In this post, I cover how &lt;a href="https://docs.fauna.com/fauna/current/build/integration/cloudflare/?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;Fauna and Cloudflare Workers&lt;/a&gt; empower you to build, deploy, and scale globally without compromising on true serverless simplicity, easy global scaling, and the ability to evolve applications without downtime.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50gk3j8q75kdly25r3q4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50gk3j8q75kdly25r3q4.png" alt="an image showing the global distribution and connectivity of Cloudflare Workers and Fauna together." width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But don't just take my word for it; ask &lt;a href="https://fauna.com/blog/how-connexin-delivers-world-class-broadband-and-smart-city-services?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;Cameron Bell, Head of Software, Systems, &amp;amp; Data at Connexin shared&lt;/a&gt;, "Fauna is a true serverless database. This is very important for applications like ours where much of the infrastructure – like Cloudflare Workers – is connectionless and requires solutions that can meet the demands of real-time, operational data. The serverless attributes of Cloudflare and Fauna mean we can genuinely do more, faster."&lt;/p&gt;

&lt;h2&gt;
  
  
  True serverless: No provisioning, replication, or clustering
&lt;/h2&gt;

&lt;p&gt;One of the core tenets of a serverless architecture is zero operational overhead. Fauna and Cloudflare’s integration lets you forget about provisioning servers, configuring clusters, or handling complex replication. Fauna’s &lt;a href="https://fauna.com/product/document-relational?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;document-relational model&lt;/a&gt; natively supports &lt;a href="https://fauna.com/product/distributed-transaction-engine?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;data consistency across multiple regions&lt;/a&gt;, and Cloudflare’s global edge network seamlessly distributes workloads. This combination allows your application to scale automatically based on usage, giving you all the benefits of global performance without needing to manage infrastructure. In other words, the architecture scales to your application’s needs—without requiring you to manage the backend setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ultra-fast multi-region and edge workloads with strong consistency
&lt;/h2&gt;

&lt;p&gt;When it comes to applications that serve a global audience, speed and data consistency are essential. Traditional databases struggle to provide both, often sacrificing one for the other. Fauna’s distributed transaction engine provides data consistency across all regions in a region group without the lag of traditional replication methods. In addition, your data is always strongly consistent across those regions. Paired with &lt;a href="https://workers.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare Workers&lt;/a&gt; and their edge network, your application can support ultra-low-latency requests around the globe, and your app always connects to the closest Fauna replica. This setup not only ensures fast responses but also guarantees consistency, letting users access the most up-to-date data with low latency, no matter where they’re located.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rapid time-to-market with simplified deployments
&lt;/h2&gt;

&lt;p&gt;With &lt;a href="https://docs.fauna.com/fauna/current/build/integration/cloudflare/?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;Fauna’s native integration with Cloudflare Workers&lt;/a&gt;, app development is accelerated by eliminating development and infrastructure management tasks. Fauna’s database enables instant global access through its API, which communicates over HTTPS, so your app can connect securely using Fauna’s client libraries or make direct HTTPS requests. This native integration means Cloudflare Workers can interact directly with Fauna without needing traditional database connection pools, &lt;a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping" rel="noopener noreferrer"&gt;ORMs&lt;/a&gt;, middleware, or complex backend setups. This makes data handling within your Cloudflare Workers faster, more efficient, and easier to manage over time.&lt;/p&gt;

&lt;p&gt;By reducing development steps from start to deployment, Fauna and Cloudflare enable you to skip backend infrastructure management, allowing you to focus entirely on building features. The streamlined connection keeps your code lean and responsive, helping you to bring products to market faster, while delivering a scalable, high-performance experience to your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep applications lightweight, performant, and easy to maintain
&lt;/h2&gt;

&lt;p&gt;Complex app logic often makes apps slower to execute, tricky to test, and difficult to manage over time. &lt;a href="https://docs.fauna.com/fauna/current/learn/query/?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;Fauna’s powerful query language&lt;/a&gt;, FQL, enables you to build complex data relationships without writing extensive application code. With &lt;a href="https://docs.fauna.com/fauna/current/learn/schema/user-defined-functions/?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;Fauna’s UDFs (user-defined functions)&lt;/a&gt;, you can embed FQL code to run in the database. This streamlined data management means that, within Cloudflare Workers, your logic remains lean and focused. Fauna handles the heavy lifting of relational data and consistency, enabling your application to remain lightweight and performant—even as it scales to meet global demand. In addition, testing new application code is easier and more repeatable as the heavy lifting can be done in UDFs.&lt;/p&gt;

&lt;p&gt;Fauna also has &lt;a href="https://docs.fauna.com/fauna/current/learn/schema/#schema?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna#schema-migrations" rel="noopener noreferrer"&gt;native zero-downtime migrations&lt;/a&gt; for &lt;a href="https://fauna.com/product/database-schema?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;database schema&lt;/a&gt; changes, which allows you to evolve your data model without taking your application offline or disrupting the user experience. As your application grows and requires changes to its data structure, you can roll out updates smoothly, maintaining high availability and minimizing the need for extensive backend reconfiguration. This enables you and your team to iterate quickly, delivering new features and products to market faster but in a controlled fashion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By combining Fauna’s flexible, distributed, and strongly consistent database with Cloudflare Worker’s edge-first architecture, you unlock a fully managed serverless stack that lets you focus on building your application, not on managing infrastructure. This partnership enables you to scale without limits, ensures ultra-fast, globally consistent data, and keeps your codebase lean—all key to getting your products to market faster and your customers happier.&lt;/p&gt;

&lt;p&gt;If you’re ready to embrace true serverless architecture, check out &lt;a href="https://docs.fauna.com/fauna/current/build/workshops/cloudflare/?utm_medium=organicsocial&amp;amp;utm_source=devto&amp;amp;utm_campaign=ch.organicsocial_tgt.developers_con.cloudflare-workers-plus-fauna" rel="noopener noreferrer"&gt;this workshop&lt;/a&gt; to see just how easy it is to get started. &lt;/p&gt;

</description>
      <category>serverless</category>
      <category>database</category>
      <category>fauna</category>
      <category>cloudflare</category>
    </item>
    <item>
      <title>DynamoDB pain points: How to address them and exploring possible alternatives</title>
      <dc:creator>Shadid Haque</dc:creator>
      <pubDate>Mon, 30 Jan 2023 14:54:50 +0000</pubDate>
      <link>https://forem.com/fauna/dynamodb-pain-points-how-to-address-them-and-exploring-possible-alternatives-ogc</link>
      <guid>https://forem.com/fauna/dynamodb-pain-points-how-to-address-them-and-exploring-possible-alternatives-ogc</guid>
      <description>&lt;p&gt;DynamoDB is a robust &lt;a href="https://fauna.com/blog/nosql-databases-non-relational-databases-explained" rel="noopener noreferrer"&gt;NoSQL database&lt;/a&gt; that has become increasingly popular due to its performance, scalability, relative simplicity, and low operational overhead. However, it has its drawbacks. Some of the main disadvantages of DynamoDB include limited querying options, limited storage capacity (400kb per document), &lt;a href="https://fauna.com/blog/compare-fauna-vs-dynamodb#consistency-models" rel="noopener noreferrer"&gt;no multi-region ACID support (eventual consistency)&lt;/a&gt;, and difficulties in replicating data in multi-region setups.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the main pain points of DynamoDB, how to overcome them, and explore some of the DynamoDB alternatives.&lt;/p&gt;

&lt;p&gt;Indeed, there are areas where DynamoDB is the most compelling solution when it comes to speed. DynamoDB is a low-latency, fully managed NoSQL database that is ideal for applications where speed is more important than strong consistency. &lt;/p&gt;

&lt;p&gt;DynamoDB automatically scales up and down (when you use provisioned capacity) based on the application traffic pattern. It supports automated sharding, so you do not need to manage shards manually. If your application requires high scalability and speed and doesn't need complex data relationships or transactions, DynamoDB is the way to go. However, Dynamo does have some drawbacks, which I will explore below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;See a &lt;a href="https://fauna.com/blog/comparison-of-serverless-databases" rel="noopener noreferrer"&gt;side-by-side comparison of serverless databases&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Limited querying capabilities
&lt;/h3&gt;

&lt;p&gt;If you have worked with DynamoDB to some extent, then you know that relational data modeling is tedious with DynamoDB. There are no foreign key joins in DynamoDB like most people are used to in relational databases. You can, however, handle complex data access patterns similar to relational databases. In DynamoDB, you can model relationships such as one-to-many, many-to-many, and one-to-one. You can use a variety of strategies, such as denormalization, duplication, and composition of primary keys.  However, these solutions require a fair amount of engineering effort and introduce a number of other limitations to consider.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Follow Alex DeBrie’s &lt;a href="https://www.alexdebrie.com/posts/dynamodb-one-to-many/" rel="noopener noreferrer"&gt;article&lt;/a&gt; to learn more about data access patterns in DynamoDB.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;DynamoDB can only perform query operations on tables with a single primary key.&lt;/em&gt;&lt;/strong&gt; Consider the following table for example. The primary key of this table is the user ID, a unique identifier for each user. The table might have other attributes like name, email, and address, as demonstrated below.&lt;/p&gt;

&lt;p&gt;You &lt;strong&gt;cannot&lt;/strong&gt; query the table on other attributes like name and email. You need to set up the &lt;strong&gt;global secondary indexes (GSI)&lt;/strong&gt; with the attributes you want to query and then use the query operation on the GSI. Those of us using DynamoDB for a while are okay with this pattern of storing data. Nevertheless, this is a limitation.&lt;/p&gt;

&lt;p&gt;Moreover, you have to consider the cost of using GSIs. GSIs consume additional read and write capacity units (RCUs and WCUs). &lt;a href="https://stackoverflow.com/questions/73250087/cost-of-adding-a-global-secondary-index-to-an-existing-dynamodb-table" rel="noopener noreferrer"&gt;Learn more about GSI costs here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's say you have a DynamoDB table called “Products” with a primary key of product_id and a few other attributes like "name" and "price". The table is provisioned with 1,000 RCUs and 1,000 WCUs. If you want to create a GSI for querying on the "name" attribute, it will require additional RCUs and WCUs to perform queries on the "name" attribute. So now you need to provision 1,000 RCUs and 1,000 WCUs for the primary key and an additional 1,000 RCUs and 1,000 WCUs for the GSI, doubling your DynamoDB usage cost. As your application grows, GSI optimization is an additional overhead you must be mindful of. In a relational database, you don't have to worry about these. &lt;/p&gt;

&lt;p&gt;Comparing a SQL database to a NoSQL database is like comparing apples to oranges. NoSQL databases such as DynamoDB are excellent for horizontal scalability, high availability, and flexibility for handling unstructured and semi-structured data. However, features such as foreign key constraints and ACID (Atomicity, Consistency, Isolation, Durability) transactions, which we take for granted in a relational database, are not present by default in DynamoDB. Manually configuring these capabilities takes a lot of engineering effort and specialized knowledge. In brief, you have to deal with increasing application complexity because of GSI.&lt;/p&gt;

&lt;p&gt;If you are exploring Amazon DynamoDB alternatives that are NoSQL and have better-querying capabilities, there are a few to choose from, but the one I will be covering here is &lt;a href="https://fauna.com/" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt;. Fauna combines the querying capabilities of relational databases (SQL databases) with the flexibility of NoSQL databases.&lt;/p&gt;

&lt;p&gt;A database management solution like &lt;a href="https://fauna.com/" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; bridges the gap between a traditional relational database and a flexible NoSQL database by allowing data to store in JSON-like documents while also giving the ability to create SQL-like data relationships among collections. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Learn more about Fauna’s &lt;a href="https://docs.fauna.com/fauna/current/learn/introduction/document_relational" rel="noopener noreferrer"&gt;document-relational model&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Like DynamoDB, Fauna is also a fully managed NoSQL database with low latency. It also auto-scales, ensures high availability, and adapts to your application traffic. DynamoDB has been around for 10+ years now, whereas Fauna is relatively new.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges of multi-region data replication
&lt;/h2&gt;

&lt;p&gt;While DynamoDB global tables provide a way to replicate data across multiple regions, it can be a complex and costly process that requires additional setup, management, and code — and it may only support some features or data replication across all indexes.&lt;/p&gt;

&lt;p&gt;You have to create the same table in multiple regions with the same schema, indexes, and throughput settings. Additionally, data replication between different regions needs to be configured and managed. There is no zero-configuration solution to replicate data across multiple regions with DynamoDB.&lt;/p&gt;

&lt;p&gt;Furthermore, certain features are not available in global tables. &lt;strong&gt;DynamoDB Time to Live&lt;/strong&gt; (TTL), which is the ability to expire items after a specified period of time, is not available with global tables.&lt;/p&gt;

&lt;p&gt;Another unsupported feature is &lt;strong&gt;DynamoDB Streams&lt;/strong&gt;. Additionally, &lt;strong&gt;local secondary indexes (LSIs)&lt;/strong&gt; and &lt;strong&gt;global secondary indexes (GSIs)&lt;/strong&gt; are not replicated across all replicas in global tables. You must manually create those LSIs and GSIs in different regions; otherwise, you cannot query data efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;em&gt;DynamoDB global tables do not provide fault-tolerant support by default&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In the case of an outage or a failure in one region, DynamoDB does not automatically switch to another region to ensure data availability.&lt;/p&gt;

&lt;p&gt;If distributed data across many regions is one of the core requirements of your application, you are better off using one of the alternatives of DynamoDB, such as Amazon Aurora, Fauna, or Apache Cassandra.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DynamoDB uses an "eventual consistency" model for global data&lt;/strong&gt;, meaning that updates may take some time to propagate to all replicas fully.&lt;/p&gt;

&lt;p&gt;Applications that require immediate consistency across all regions may need to use a different database solution or implement additional logic to handle eventual consistency in DynamoDB. Since data may not be immediately available in all regions, read and write operations may be slower in certain regions. This can affect the performance and user experience of the application.&lt;/p&gt;

&lt;p&gt;Fauna is one of the strong competitors to Amazon DynamoDB for its multi-region data replication. Fauna provides multi-region data with strong consistency. It automatically routes your requests to the nearest replica, ensuring that your application experiences low latency. Fauna automatically replicates your data across all regions, ensuring that your data is always up-to-date and available — even in case of a regional outage or failure. Unlike DynamoDB, Fauna requires zero configuration for global replication. Strong data persistence in all regions is always guaranteed. If you &lt;a href="https://fauna.com/blog/comparing-fauna-and-dynamodb-pricing-features" rel="noopener noreferrer"&gt;compare Fauna to DynamoDB&lt;/a&gt;, you realize that Fauna offers all the features of DynamoDB without the drawbacks.&lt;/p&gt;

&lt;p&gt;Apache Cassandra is also another alternative to Amazon DynamoDB. It is a free, distributed wide-column, NoSQL, open source database that can handle a large amount of data across multiple regions. However, you must manage your infrastructure and clusters if you decide to use Apache Cassandra. Managing your clusters can be challenging, even though Cassandra has robust documentation and an active community behind it.&lt;/p&gt;

&lt;p&gt;Another database you may be interested in as an alternative is MongoDB Atlas, the managed service for MongoDB. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Learn how &lt;a href="https://fauna.com/blog/comparing-fauna-and-mongodb" rel="noopener noreferrer"&gt;Fauna stacks up against MongoDB&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Storage limitations
&lt;/h3&gt;

&lt;p&gt;Another pain point with DynamoDB is the item size limit. An individual item has a maximum of 400kb in size. The item size limit impacts the way data is modeled. The application may need to denormalize the data or split it across multiple items to work within the item size limit. The storage limitation is not a big deal for most applications out there, but if you plan to grow and scale your application to millions of users, you should start thinking about the additional complexity you need to handle. &lt;/p&gt;

&lt;p&gt;DynamoDB competitors such as MongoDB, Fauna, or Cassandra don't have this issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building scalable applications on DynamoDB
&lt;/h3&gt;

&lt;p&gt;DynamoDB is well known for its low latency and scalability. However, as you build and scale your application with DynamoDB, you must be aware of some common pitfalls. As discussed in the previous section, an individual item in DynamoDB can be at most 400kb. While building with DynamoDB, it is crucial to understand the data model that best fits your application's use case and design the table schema accordingly. Failing to do this at the start will cost you as you scale your application.&lt;/p&gt;

&lt;p&gt;Although possible, evolving your data with DynamoDB as your application grows is challenging. You need to choose the correct partition key. Selecting the right partition key ensures that the data is evenly distributed and read and write requests are distributed evenly across all partitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limited ability to perform advanced analytics
&lt;/h3&gt;

&lt;p&gt;DynamoDB is optimized for storing and retrieving large amounts of data quickly, but it is ill-suited for performing advanced analytics on that data. It doesn't support advanced features such as aggregate functions or window functions.&lt;/p&gt;

&lt;p&gt;SUM, COUNT, AVG, and MAX are commonly used in SQL to perform calculations on groups of data. DynamoDB alternatives MongoDB and Fauna have equivalent features to perform these analytics tasks. In MongoDB, you get aggregate functions such as $group, $match, $project, etc. Fauna also provides aggregate functions through Fauna Query Language (FQL) for advanced analytics.&lt;/p&gt;

&lt;p&gt;Window functions are another advanced SQL feature that DynamoDB does not support. These functions allow users to perform calculations over a set of rows related to the current row in a query. Fauna also does not have built-in window functions, but it is possible to perform calculations similar to window functions using the Map-Reduce function and a combination of other functions. MongoDB does not have built-in window functions either. However, it does have the $bucket operator, which can be used to perform similar calculations.&lt;/p&gt;

&lt;p&gt;If you insist on using DynamoDB and need robust analytics, then your best bet is to use third-party analytics tools such as Apache Hive or Apache Pig to perform complex queries and advanced analytics on the data stored in DynamoDB. You have to consider the additional cost of these extra resources, however.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To conclude, DynamoDB is well-suited for use cases that require high scalability, high performance, and low latency. It seamlessly integrates with other AWS services and supports document and key-value data models. However, it also comes with its limitations. Limited query capabilities, little support for the transaction, eventual consistency, and limited support for analytics are some of the main pain points with DynamoDB. With enough engineering resources and time, you can overcome these pain points.&lt;/p&gt;

&lt;p&gt;Everything in software engineering is about tradeoffs. Every database management solution has its pros and cons. It is up to you and the developers to choose your company's best solutions. This article gives you a clear picture of the various limitations of DynamoDB and some of the alternatives to DynamoDB so you can make the best-informed decision while choosing a database for your next project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Though DynamoDB has much to offer, Fauna is a much newer offering that comes with a host of powerful and unique features that enhance the serverless experience for organizations of all sizes. Read more at “&lt;a href="https://fauna.com/blog/modernization-of-the-database-dynamodb-to-fauna" rel="noopener noreferrer"&gt;Modernization of the database: DynamoDB to Fauna&lt;/a&gt;.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;If you're experiencing any of the DynamoDB pain points mentioned above and are looking for a more robust and efficient solution, consider reaching out to either me or the &lt;a href="https://go.fauna.com/compare/dynamodb" rel="noopener noreferrer"&gt;team of experts&lt;/a&gt; at Fauna.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>serverless</category>
      <category>database</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Modernizing from PostgreSQL to Serverless with Fauna Part 1 (2023 Update)</title>
      <dc:creator>Luis Eduardo Colon</dc:creator>
      <pubDate>Mon, 09 Jan 2023 16:49:06 +0000</pubDate>
      <link>https://forem.com/fauna/modernizing-from-postgresql-to-serverless-with-fauna-part-1-2023-update-42kj</link>
      <guid>https://forem.com/fauna/modernizing-from-postgresql-to-serverless-with-fauna-part-1-2023-update-42kj</guid>
      <description>&lt;p&gt;&lt;em&gt;With modern development practices and efficiencies in mind, you can transition from a traditional relational application to a serverless document-relational database with maximum scale and no data consistency compromises.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2l0uupqhyv46hxzgpvly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2l0uupqhyv46hxzgpvly.png" alt="Moving from PostgreSQL to FaunaDb" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Many web and mobile applications continue to be implemented atop traditional relational databases. Although many core components of these databases are five decades old, these designs are the most familiar to most database professionals. However, recently the choices have shifted toward more distributed, cloud-native options to support hyper-scale expectations.&lt;/p&gt;

&lt;p&gt;One of the popular relational database options is &lt;a href="https://www.postgresql.org" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; (A.K.A. Postgres), which dates back to UC Berkeley’s POSTGRES project in 1986. It has supported SQL since 1994 and has been ACID compliant since 2001. Like other popular relational databases, Postgres is a client-server database at its core and continues to be enhanced by an active community, with Version 15 released in late 2022.  &lt;/p&gt;

&lt;p&gt;Over its long history, Postgres has added a large set of extensions and options, including almost a dozen different data indexing options and many server replication alternatives. Multiple vendors have added data distribution options atop the core server code. In contrast, other vendors offer so-called “wire-level” compatibility atop redesigned engines that look more like less traditional key-value stores. However, most of the newest implementations still necessarily expose significant operational complexity in areas like partitioning complexity. &lt;/p&gt;

&lt;p&gt;Some of the largest websites, driven by the requirements of serving billions of users, have led to the maturation of new database architecture alternatives, which motivate modernizing applications to leverage cloud-native, serverless, highly-distributed database options. &lt;a href="https://fauna.com/" rel="noopener noreferrer"&gt;Fauna&lt;/a&gt; strengthens relational data consistency among these newer alternatives while leveraging a cloud-native, serverless, flexible document model that abstracts most operational complexities from application developers. &lt;/p&gt;

&lt;p&gt;You may be an application developer looking to build an application designed to scale well from the beginning. Or, you are a database professional looking to transition a Postgres application to minimize the amount of scaling impediments you may have encountered periodically as you continue building features. In either case, this article series is for you. This first of three articles is an updated version of an &lt;a href="https://fauna.com/blog/modernizing-from-postgresql-to-serverless-with-fauna-part-1" rel="noopener noreferrer"&gt;existing&lt;/a&gt; tutorial built by Brecht De Rooms some time ago. It explores the process of transitioning an existing Postgres application to Fauna while ensuring that you build your database in a scalable way from the beginning.  &lt;/p&gt;

&lt;p&gt;In this first part, we’ll provide a deep comparison between Fauna and Postgres while we explore how to implement and query a one-to-many relationship in a basic database. In &lt;a href="https://fauna.com/blog/modernizing-from-postgresql-to-serverless-with-fauna-part-2" rel="noopener noreferrer"&gt;part two&lt;/a&gt;, we extend the concepts to cover a many-to-many relationship and how to build a domain-specific language that avoids object-relational impedance mismatches. We explore advanced transactions with referential integrity in &lt;a href="https://fauna.com/blog/modernizing-from-postgresql-to-serverless-with-fauna-part-3" rel="noopener noreferrer"&gt;part three&lt;/a&gt; and suggest various modeling, optimization, and migration strategies. &lt;/p&gt;




&lt;h3&gt;
  
  
  Comparing Postgres and Fauna
&lt;/h3&gt;

&lt;p&gt;Given that both Postgres and Fauna support relational database features, they share many important characteristics. Both support data relationships, serializable transactions, normalization, foreign keys, indexes, constraints, stored procedures, and many other typical relational database features. Both support ACID transactions and strict isolation levels, with Fauna default isolation levels can be considered stricter since it provides those guarantees even when data is distributed. Both are primarily aimed and are well suited for online transaction processing (OLTP) applications.  Fauna focuses more on this use case because it is designed as a cloud-native database optimized for sub-second queries. At the same time, many Postgres implementations and extensions can be suited for more analytical use cases. &lt;/p&gt;

&lt;h4&gt;
  
  
  Notable Differences
&lt;/h4&gt;

&lt;p&gt;Although both databases can implement most database requirements, their implementation varies significantly in some areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Relational-model vs multi-model:&lt;/strong&gt; Postgres is often described as an object-relational database with additional data types that support documents like JSON and JSONB, but it is primarily built and used as a traditional relational database. Fauna is often described as a document-relational database with JSON documents at its core.  In contrast to other common document databases, it offers relational options and flexible indexing to maintain consistency. Further, it adds temporality and graph-like features such as graph traversal.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schemas:&lt;/strong&gt; Both Postgres and Fauna have a concept of logical databases that include schema records describing the collections, indexes, and security properties of the included records.  However, Postgres enforces schemas while Fauna is considered schema-less in that it supports adding additional fields or attributes, while still providing mechanisms to enforce integrity and uniqueness. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database connections:&lt;/strong&gt; Postgres expects persistent connections, like many similar relational databases.  Most implementations must configure connection pools and have to be concerned with connection overhead and limits.  Fauna uses stateless, secure HTTP connections and requires no connection management. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database as an API:&lt;/strong&gt; Postgres is built to self-host or to be hosted or managed by cloud providers, requiring managing server instances, read replicas, partitioning, and the like.  There are vendors that claim that they provide serverless Postgres, but in many cases, there are still provisioning decisions to consider.  On the other hand, Fauna is delivered as an API with a single global endpoint, and there are no clusters, partitions, and replication to configure.  Furthermore, the single global endpoint can intelligently route a request to the closest copy of the data. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution:&lt;/strong&gt; When it comes to distribution in a traditional database, asynchronous replication is the most popular form of distribution which introduces eventual consistency and potential data loss. If consistency is required, &lt;a href="https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION-PERFORMANCE" rel="noopener noreferrer"&gt;synchronous replication&lt;/a&gt; is provided as an option, but it typically comes at a high price in terms of performance, especially if distribution across regions is desired. Although traditional databases like Postgres were not built with distribution in mind, many recent improvements and additions provide multiple options that supplement the non-distributed nature of its core engine. In contrast, Fauna is built from the ground up as a scalable, multi-region distributed database. It is inspired by the &lt;a href="https://css-tricks.com/consistent-backends-and-ux:-how-do-new-algorithms-help/" rel="noopener noreferrer"&gt;Calvin&lt;/a&gt; algorithm that speeds up data consensus by relying on deterministic calculations.  Further, this distribution of data is transparent to the application developers and can accommodate data locality restrictions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenancy:&lt;/strong&gt; Although Postgres provides various options to create a SaaS application where you can have multiple tenants (whether across servers or within a single database), Fauna has a unique concept of child databases with arbitrarily deep nesting.  Child databases are completely isolated from each other, with the ability to create separate permissions for child databases, and the child databases cannot determine whether there’s a parent database. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Languages:&lt;/strong&gt; The primary language used for Postgres is SQL or, more accurately, a SQL dialect.  Although SQL has been around for many decades and is well known, documented, and standardized to the extent that it can be, every SQL database exhibits significant variations in the language. For example, to support JSON manipulation and event streaming, you will encounter significant differences between the SQL commands used in Postgres and other SQL databases like MySQL. Application developers will likely use an object-relational mapper (ORM) that adds some application complexity without removing the need to understand the Postgres-specific SQL conventions. GraphQL can be used with Postgres by adding extensions, of which there are many options to consider.  Fauna provides its own native query language, FQL, which is designed to align with modern coding paradigms.  Because of the nature of FQL and other design considerations, Fauna requires no ORM and is not susceptible to injection. The choice for a custom language is rooted in Fauna's scalable and distributed design. It’s designed to prevent long-running transactions, maximize performance in distributed scenarios, be highly composable to reduce round-trips, and have a transparent and predictable query plan. Many of these characteristics will become evident in this article and its subsequent parts as we cover FQL extensively in the coming sections. Beyond FQL, Fauna also supports GraphQL out of the box. &lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Postgres and Fauna: Terminology Mapping
&lt;/h4&gt;

&lt;p&gt;The following table summarizes how Fauna concepts relate to Postgres counterparts and, in most cases, also apply to similar terms used with other relational databases. This table comes from this &lt;a href="https://fauna.com/blog/compare-fauna-vs-postgres" rel="noopener noreferrer"&gt;blog&lt;/a&gt;, and the Fauna documentation provides more details on these concepts and many other common SQL commands and concepts &lt;a href="https://docs.fauna.com/fauna/current/learn/introduction/fql_for_sql_users" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;POSTGRES&lt;/th&gt;
&lt;th&gt;FAUNA&lt;/th&gt;
&lt;th&gt;DETAILS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Row or record&lt;/td&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;In Postgres, a record (or row) represents a distinct database entry, and it must conform to the containing table’s column definitions. In Fauna, a document represents a nested structure of fields and their values, with no specified structure or types. Each document, even in the same collection, can have its own independent structure, making the documents schemaless. Also, each document is versioned, storing the history of a document’s mutations from creation to deletion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table&lt;/td&gt;
&lt;td&gt;Collection&lt;/td&gt;
&lt;td&gt;Tables store records, collections store documents. In Postgres, a table’s column definition specifies the structure for all records in the table. The column definition specifies the names and types of values that can be stored in a column. In Fauna, collections are a container for documents, imposing no specific structure on those documents.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary&lt;/td&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;Fauna has no primary or secondary concept, all regions can serve reads and writes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secondary, standby, replica&lt;/td&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;Fauna has no primary or secondary concept, all regions can serve reads and writes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replication&lt;/td&gt;
&lt;td&gt;Replication&lt;/td&gt;
&lt;td&gt;Fauna’s replication is semi-synchronous and does not require any operator management.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sharding, partitioning&lt;/td&gt;
&lt;td&gt;Not Applicable&lt;/td&gt;
&lt;td&gt;Fauna does not require the operator to manage sharding or partitioning in any way.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary Key&lt;/td&gt;
&lt;td&gt;Reference (Ref)&lt;/td&gt;
&lt;td&gt;The unique identifier of a document.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Foreign Key&lt;/td&gt;
&lt;td&gt;Reference (Ref)&lt;/td&gt;
&lt;td&gt;A pointer from one document to another.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index, materialized view&lt;/td&gt;
&lt;td&gt;Index&lt;/td&gt;
&lt;td&gt;Fauna merges the concepts of indexes and views. Indexes must be explicitly referenced.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transaction&lt;/td&gt;
&lt;td&gt;Transaction&lt;/td&gt;
&lt;td&gt;Both Postgres and Fauna support ACID transactions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schema, database&lt;/td&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Both Postgres and Fauna have a concept of logical databases that include schema records describing the collections, indexes, and security properties of the included records. In Postgres and other relational databases, a schema refers to the set of table definitions and constraints defined in that database. The schema is enforced so that no row violates its table definition or constraints. In Fauna, database definitions also include child databases with arbitrarily deep nesting. A Fauna database contains schemaless documents with no schema enforcement available at the document level; however, validation functions may be used when necessary. The Fauna GraphQL API does apply schema enforcement to comply with GraphQL schemas.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stored procedures, user-defined functions&lt;/td&gt;
&lt;td&gt;User Defined Functions (UDF) or Functions&lt;/td&gt;
&lt;td&gt;Fauna supports user-defined functions written in FQL.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tables and rows are collections and documents in Fauna just like in other document databases. An index in Fauna combines an index and a view as we know them in a traditional database. We’ll directly query indexes for data since indexes contain data, similar to consistent ordered views. User Defined Functions (UDFs) are similar to Stored Procedures except that, in contrast to Postgres, both queries and UDFs are written in the same language in Fauna, while in Postgres, you would split to the &lt;a href="https://www.postgresql.org/docs/15/plpgsql.html" rel="noopener noreferrer"&gt;PL/pgSQL&lt;/a&gt; language for a stored procedure. Fauna users typically use UDFs much more frequently due to the easy transition from a query to a UDF.&lt;/p&gt;




&lt;h3&gt;
  
  
  From Postgres to Fauna: Building the Basics
&lt;/h3&gt;

&lt;p&gt;In this section, we’ll learn how to create a database, a collection, insert some documents, and query them.  We will focus on modeling a one-to-many relation in this article; we will model a many-to-many relation in the next article and cover other modeling options in the third and last installment. We’ll use a well-known &lt;a href="https://www.postgresqltutorial.com" rel="noopener noreferrer"&gt;Postgres tutorial&lt;/a&gt; that provides a database model of a &lt;a href="https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/" rel="noopener noreferrer"&gt;DVD rental business&lt;/a&gt;. The model of the DVD rental application looks as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlsk2ylq4mr6bpbut52v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlsk2ylq4mr6bpbut52v.png" alt="ERD for Sample DVD Rental Business" width="800" height="1001"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Fig. 1.&lt;/strong&gt;Entity relationship diagram for DVD rental business. Source: &lt;a href="https://www.postgresqltutorial.com/postgresql-sample-database/" rel="noopener noreferrer"&gt;PostgreSQL Tutorial&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The database schema has &lt;strong&gt;“film"&lt;/strong&gt; at its center and allows customers to rent DVDs from different stores around the country, supports shopping baskets, as well as film, payment, store, and customer management. Thanks to the normalized model, it supports many access patterns: customers can find films by category, rating, release year, title, description, or actor. The staff can retrieve where a film currently resides or retrieve a list of overdue rentals.&lt;/p&gt;
&lt;h4&gt;
  
  
  Creating a new database
&lt;/h4&gt;

&lt;p&gt;In this section, we’ll create the database. Even if you don’t follow along, this 2-click process (plus typing a name) shows how different the database-creation process is compared to setting up a traditional database.&lt;/p&gt;
&lt;h5&gt;
  
  
  Sign Up
&lt;/h5&gt;

&lt;p&gt;Fauna is a cloud database. There is no setup of hardware or configuration necessary. All you need to do is go to &lt;a href="https://dashboard.fauna.com" rel="noopener noreferrer"&gt;dashboard.fauna.com&lt;/a&gt; and sign up for an account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9ljk6m8e8prua2q5lyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9ljk6m8e8prua2q5lyh.png" alt="Fauna Sign Up Screen" width="580" height="708"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Create the database
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8l686lvebs9o2r03c530.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8l686lvebs9o2r03c530.png" alt="Create a new database screen" width="582" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;NEW DATABASE&lt;/strong&gt; to create a new database which will instantly be created.&lt;/p&gt;

&lt;p&gt;Fill in a name for your database and click &lt;strong&gt;CREATE&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now that you have created a database, you can follow along by pasting the provided code in the dashboard shell (or play around with the UI instead to create collections/indexes etc). Of course, you can also send queries to Fauna using one of the &lt;a href="https://docs.fauna.com/fauna/current/drivers/javascript.html?lang=javascript" rel="noopener noreferrer"&gt;drivers&lt;/a&gt; or the terminal &lt;a href="https://docs.fauna.com/fauna/current/build/tools/shell/" rel="noopener noreferrer"&gt;shell&lt;/a&gt;. The shell is built around the JavaScript driver behind the scenes. When writing FQL, we are not writing strings but rather functions, although that might not be obvious as we use the dashboard shell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5q9payt6rf4izki4e68u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5q9payt6rf4izki4e68u.png" alt="Fauna Dashboard Screen" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  One-to-Many relations
&lt;/h4&gt;

&lt;p&gt;Let’s start with a small and easy subset of the model and extend it gradually. The film and language relation is a many-to-one relation that should be very easy to model. Since the model remains quite simple, we’ll add a few things now and then in green to render it more interesting. Instead of one language, we’ll add both a spoken and a subtitle language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyamgxueu9ttmo9vzvvo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyamgxueu9ttmo9vzvvo.png" alt="Updating the ERD to add a one-to-many relationship." width="800" height="608"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Fig. 2.&lt;/strong&gt;Adding a one-to-many relationship for both spoken and subtitle language.&lt;/em&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Creating the language collection
&lt;/h5&gt;

&lt;p&gt;In Postgres, we have tables that contain rows; in Fauna, we have collections that contain documents. To create a new film collection, we could use the dashboard interface but just like in SQL, manipulation and creation of collections, indexes, security roles, or even databases can be done entirely in the query language. To create the film collection, we can also paste the following code snippet in the dashboard shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;CreateCollection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Creating a language document
&lt;/h5&gt;

&lt;p&gt;We can create the equivalent document for the language as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/createfunction?lang=javascript" rel="noopener noreferrer"&gt;Create()&lt;/a&gt; function is used to create documents, similar to an Insert statement in Postgres. It takes the collection where you want to store the document as the first parameter and a JSON object as the second. Application data is always nested under the &lt;strong&gt;data&lt;/strong&gt; key, which separates it from special Fauna fields. Once we have executed the Create() statement, we can take a look at the document by going to the &lt;strong&gt;Collections&lt;/strong&gt; tab in the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2v7f9ldyjnsmuk70537.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2v7f9ldyjnsmuk70537.png" alt="Created language document" width="800" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fauna has automatically generated two fields: ref and ts, which are the Fauna equivalent of id and last_update.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ref:&lt;/strong&gt; a unique reference to the document. The presence of references doesn’t mean that we can no longer use other IDs in Fauna. We’ll see the difference between native Fauna references and IDs shortly when we start querying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ts:&lt;/strong&gt; the document's timestamp, which is automatically updated when the document is adapted. Fauna’s timestamp is part of &lt;a href="https://docs.fauna.com/fauna/current/build/fql/temporality?lang=javascript" rel="noopener noreferrer"&gt;temporality&lt;/a&gt; features that provide time travel and support the &lt;a href="https://fauna.com/blog/live-ui-updates-with-faunas-real-time-document-streaming" rel="noopener noreferrer"&gt;streaming&lt;/a&gt; capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: Your reference IDs will be different. If you are following along, you can grab the reference ID of any document from the dashboard's Collections view.&lt;/em&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Creating the film documents
&lt;/h5&gt;

&lt;p&gt;To store the film documents, we need a new collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;CreateCollection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s create a couple of simplified film documents. We actually have many potential choices for the relation between films and languages (at least five) since Fauna is both a document and relational database. However, anything that is not normalized is typically an optimization so let’s start with the normalized model.&lt;/p&gt;

&lt;p&gt;We will make it more interesting and add both spoken language and subtitles language. We will refer to the previously created language by storing the native reference in the document as follows (again, your reference IDs will be different):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Academy Dinosaur&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;spoken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;288878259769180673&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;subtitles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;288878259769180673&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A second document might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;Back&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;Future&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,
        language: {
            spoken: Ref(Collection(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;), &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="mi"&gt;288878259769180673&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;),
            subtitles: Ref(Collection(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;), &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="mi"&gt;288878259769180673&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)
        }
      }
    }
  )
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An alternative approach is to add the languages as embedded objects. If we do not intend to efficiently query languages directly, we could add it as an embedded object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Academy Dinosaur&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;spoken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;subtitles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Embedding vs normalized data
&lt;/h5&gt;

&lt;p&gt;Fauna is a document database that might make us think: “don’t join data, duplicate it” as a workaround due to the limitations of popular document databases. Since Fauna is relational, such workarounds are not necessary but rather another option in your tool belt. This is an important consideration when working with Fauna versus other document databases: denormalization is a choice, not a workaround. &lt;/p&gt;

&lt;p&gt;Postgres is not natively a document database but has, among its options, a JSONB type that can be used to emulate documents. However, such columns do not benefit from &lt;a href="https://www.2ndquadrant.com/en/blog/postgresql-anti-patterns-unnecessary-jsonhstore-dynamic-columns/" rel="noopener noreferrer"&gt;optimizations&lt;/a&gt; such as column statistics, are restricted to primitive operations, lack built-in functions to &lt;a href="https://stackoverflow.com/questions/26703476/how-to-perform-update-operations-on-columns-of-type-jsonb-in-postgres-9-4" rel="noopener noreferrer"&gt;modify values&lt;/a&gt;, and may be awkward to query in SQL. The absence of column statistics blinds the query planner, resulting in potential &lt;a href="https://www.heap.io/blog/when-to-avoid-jsonb-in-a-postgresql-schema" rel="noopener noreferrer"&gt;production issues&lt;/a&gt;. In light of these limitations, you might resort to storing frequently queried attributes in regular columns and the remainder in JSONB columns.&lt;/p&gt;

&lt;p&gt;In contrast, Fauna's querying and indexing capabilities do not change based on whether documents contain nested data or normalized. That doesn’t mean that denormalization is the recommended practice, but it does become more attractive as a technique to optimize read performance. We'll dive into some advanced optimization techniques at the end of this series and show how FQL can help you hit the sweet spot between flexibility, optimization, and data correction.&lt;/p&gt;

&lt;p&gt;In some databases, indexing flexibility might suffer when nesting objects. However, Fauna’s indexing is built to be flexible regardless of whether the data is stored as nested objects or normalized. Further, Fauna indexes work equally well on nested values or arrays. For example, we could index the spoken language by adding the following path data &amp;gt; language &amp;gt; spoken &amp;gt; name to the index. If spoken languages had been an array instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Academy Dinosaur"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;language:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;spoken:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"French"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;subtitles:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can add the same path to the index, and Fauna will recognize that it’s an array and unroll it. By using advanced features like &lt;a href="https://docs.fauna.com/fauna/current/build/fql/indexes/bindings?lang=javascript" rel="noopener noreferrer"&gt;index bindings&lt;/a&gt;, we can even combine both the spoken and subtitles language in one index to find any film in a specific language, regardless of whether it’s the spoken or subtitle language.&lt;/p&gt;

&lt;p&gt;Before we talk about the trade-offs and even more alternative strategies, let’s see how we would retrieve films and then perform a simple join by including languages.&lt;/p&gt;

&lt;h5&gt;
  
  
  Querying a collection
&lt;/h5&gt;

&lt;p&gt;The simplest Postgres query is easy since SQL is a declarative language where you describe what you need instead of how you want it to be calculated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;film&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In contrast, FQL is a procedural language, like PL/pgSQL. Although it’s initially verbose, we’ll discover that we can extend the language to tame that verbosity.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article focuses on replicating a traditional relational model in Fauna, providing an opportunity to introduce you to FQL. If you want to dive deeper into the fundamentals of FQL, &lt;a href="https://docs.fauna.com/fauna/current/learn/tutorials/fql/basics/" rel="noopener noreferrer"&gt;here&lt;/a&gt; is an excellent guide that starts from scratch, and here's a &lt;a href="https://docs.fauna.com/fauna/current/learn/introduction/fql_for_sql_users#sql-to-fql-transpiler" rel="noopener noreferrer"&gt;guide&lt;/a&gt; to translating basic SQL queries to FQL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Retrieving all documents starts by executing the &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/documents?lang=javascript" rel="noopener noreferrer"&gt;Documents()&lt;/a&gt; function on a collection. The &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/collection?lang=javascript" rel="noopener noreferrer"&gt;Collection()&lt;/a&gt; function returns the reference to the collection, and Documents() retrieves the film references from that collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When executing this first query snippet, you might be surprised that it simply returns something like “ok, here is a reference to a set of films” but not the actual film documents yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@set"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;documents:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Collection(&lt;/span&gt;&lt;span class="s2"&gt;"film"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like SQL, FQL is inspired by relational algebra. In FQL, we construct sets. For example, we could combine the above statement with other sets using familiar functions such as &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/union?lang=javascript" rel="noopener noreferrer"&gt;Union()&lt;/a&gt;, &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/difference?lang=javascript" rel="noopener noreferrer"&gt;Difference()&lt;/a&gt;, &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/distinct?lang=shell" rel="noopener noreferrer"&gt;Distinct()&lt;/a&gt;. A set is merely a definition of the data we would like to retrieve but has yet to be a concrete dataset.&lt;/p&gt;

&lt;p&gt;Although it might seem like strings if we use the dashboard shell, we are actually using functions from the underlying JavaScript driver. Try misspelling a function in the dashboard shell, and you’ll get a familiar &lt;code&gt;&amp;lt;function&amp;gt; undefined&lt;/code&gt; error. Or write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to copy the whole statement simultaneously, as the dashboard shell does not maintain variables between runs.&lt;/p&gt;

&lt;p&gt;That JavaScript variable now contains our query definition, and we can use the variable to continue composing our query in a much more elegant way than string concatenation could allow. Many users use this to &lt;a href="https://github.com/shiftx/faunadb-fql-lib" rel="noopener noreferrer"&gt;extend&lt;/a&gt; the language or construct their own DSL, which we will show extensively in the rest of the article.&lt;/p&gt;

&lt;h5&gt;
  
  
  Pagination
&lt;/h5&gt;

&lt;p&gt;To materialize a set and retrieve the data, calling the &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/paginate?lang=javascript" rel="noopener noreferrer"&gt;Paginate()&lt;/a&gt; function is mandatory; this is an important measure to ensure scalability and to always keep transactions relatively small.  This is a common best practice when consuming most interactive APIs. Since we added two films, we can add a size parameter to see the pagination in action. Fauna will return an after cursor to move to the next page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which now returns a Page of film references:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;after:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"film"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"288877928042725889"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"film"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"288801457307648519"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Once we call Pagination, our set is transformed to a Page. The &lt;a href="https://docs.fauna.com/fauna/current/learn/understanding/types?lang=javascript" rel="noopener noreferrer"&gt;data types documentation&lt;/a&gt; lists which functions can be called on Sets, Pages, Arrays, etc.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can then copy the after cursor to get to the next page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;288877928042725889&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data architects who have experimented with &lt;a href="https://www.citusdata.com/blog/2016/03/30/five-ways-to-paginate/" rel="noopener noreferrer"&gt;multiple ways of pagination&lt;/a&gt; within Postgres may want to know what kind of pagination this is. Fauna’s approach is close to the KeySet approach and cleverly takes advantage of snapshots to ensure that pages do not change when data is adapted. This is possible since everything we query in Fauna is backed by a sorted index. Just like Paginate, indexes are mandatory to avoid issuing underperforming queries.&lt;/p&gt;

&lt;p&gt;Although we don’t seem to be using an index in the query above, Documents() is actually using a built-in index sorted by reference. By including pagination, the query above is actually more similar to the following query but with a superior form of pagination since the default &lt;a href="https://docs.fauna.com/fauna/current/learn/tutorials/fql/indexes/pagination" rel="noopener noreferrer"&gt;page size&lt;/a&gt; in Fauna is 64:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;film&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Function Composition
&lt;/h5&gt;

&lt;p&gt;In the previous queries, we only returned document references. To transform these references into the complete document data, making it more equivalent to a &lt;code&gt;SELECT *&lt;/code&gt;, we will loop over these references with the &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/map?lang=javascript" rel="noopener noreferrer"&gt;Map()&lt;/a&gt; FQL function and call &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/get?lang=javascript" rel="noopener noreferrer"&gt;Get()&lt;/a&gt; on each of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
    &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides Map() and Get(), we introduced &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/lambda?lang=javascript" rel="noopener noreferrer"&gt;Lambda()&lt;/a&gt; and &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/var?lang=javascript" rel="noopener noreferrer"&gt;Var()&lt;/a&gt; in the code snippet above. Lambda() is the FQL name for a simple anonymous function, which we can pass to Map to be executed on each element. Var() is used to retrieve an FQL variable (in this case, the parameter passed to Lambda).  At this point, you may be wondering: can’t we retrieve the complete document directly instead of using Map()? We can do so by adding more values to the index, and we’ll extensively address the trade-offs when we talk about optimizations in the third article.&lt;/p&gt;

&lt;p&gt;Why use the Var() and Lambda() syntax here? As mentioned before, we are composing the query by calling JavaScript functions. Using strings like “ref” as variables, and retrieving them with Var(), helps keep JS variables separate from FQL variables. The advantage of writing your query by composing JavaScript functions lies in the extensibility. For example, we can extend FQL by writing a simple function equivalent to a simple &lt;code&gt;SELECT *&lt;/code&gt; in SQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SelectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
        &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this function definition, we would then call it as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;SelectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This composability allows you to use Fauna in ways that would be infeasible or incredibly hard in other databases, as we’ll see later when we cover optimization strategies. A prime example is the Fauna GraphQL query which compiles one-to-one to FQL, maintaining the same database guarantees. This is relatively easy in Fauna but requires advanced techniques in traditional databases.&lt;/p&gt;

&lt;h4&gt;
  
  
  Querying a one-to-many relation: multiple options
&lt;/h4&gt;

&lt;p&gt;Whether we decide to embed the additional data in a collection document or use explicit references, we have multiple options to retrieve the data related in our one-to-many relation. &lt;/p&gt;

&lt;h5&gt;
  
  
  Querying embedded documents
&lt;/h5&gt;

&lt;p&gt;If we had embedded the language document by storing the languages directly in the film document, we would not have to change the query, simply returning the film documents would include the languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
    &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieving the film document with Get() would immediately return the complete document, including the languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;ref:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"film"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"289321621957640705"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1612177450050000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Academy Dinosaur"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;language:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;spoken:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;subtitles:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Querying normalized data with native references
&lt;/h5&gt;

&lt;p&gt;Earlier, we chose to store native references instead of embedding the documents, like we depict below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Academy Dinosaur"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;language:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;spoken:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"288878259769180673"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;subtitles:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"288878259769180673"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that we need to write the equivalent of a Postgres join. In Postgres, that would look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;film&lt;/span&gt; 
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="nv"&gt;"language"&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;spol&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;spol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;language_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;film&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spoken_language_id&lt;/span&gt; 
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="nv"&gt;"language"&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;subl&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;subl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;language_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;film&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subtitles_language_id&lt;/span&gt; 
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Postgres, we define the join we would like to see and rely on the query optimizer to select the right algorithm. If the query optimizer makes a wrong judgment, &lt;a href="https://www.cybertec-postgresql.com/en/join-strategies-and-performance-in-postgresql/" rel="noopener noreferrer"&gt;query performance can suffer significantly&lt;/a&gt;. Depending on the data and the way we join it, the join algorithm could differ and even change when the size of the data changes.&lt;/p&gt;

&lt;p&gt;Due to the scalable nature of Fauna, we want predictability in terms of price and performance. We have talked about set functions such as Union(), Difference(), and Distinct(), and we can accomplish this without using a &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/join?lang=javascript" rel="noopener noreferrer"&gt;Join()&lt;/a&gt; statement in Fauna yet. Although joins can scale in general, their performance will depend on many factors. To ensure predictability, we’ll join on the materialized documents after pagination. We’ll retrieve the film document within the lambda and paginate on each level, as we’ll see when we tackle many-to-many joins.&lt;/p&gt;

&lt;p&gt;Let’s continue incrementally building upon the previous query, which returns our film documents with language references.  We’ll start here, as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
    &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we'll slightly refactor it to bind variables with &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/let?lang=javascript" rel="noopener noreferrer"&gt;Let()&lt;/a&gt;, bringing more structure to our queries and rendering them more readable. Within a Let(), we can retrieve anything related to a film we desire.  Here’s our next incremental iteration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
    &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
        &lt;span class="nc"&gt;Let&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
           &lt;span class="na"&gt;film&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; 
        &lt;span class="c1"&gt;// for now, we’ll return the film variable.&lt;/span&gt;
        &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we retrieve both language references from the film document with &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/select?lang=javascript" rel="noopener noreferrer"&gt;Select()&lt;/a&gt; and get the actual languages by &lt;strong&gt;dereferencing&lt;/strong&gt; the spoken and subtitles language reference with Get().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
    &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nc"&gt;Let&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;film&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="na"&gt;spokenLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
            &lt;span class="na"&gt;subLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subtitles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// todo return&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, return these variables in the structure we specify.  We can now try this complete function in the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
    &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nc"&gt;Let&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;film&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="na"&gt;spokenLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
            &lt;span class="na"&gt;subLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subtitles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;      
        &lt;span class="c1"&gt;// return a JSON object&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;film&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;spoken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spokenLang&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="na"&gt;subtitles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subLang&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete result is now nicely structured, with both films and both languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;film:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;ref:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"film"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352445336554307667"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1672376915430000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Academy Dinosaur"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;language:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;spoken:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;subtitles:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;language:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;spoken:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ref:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1672376421400000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;subtitles:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ref:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1672376421400000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;film:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;ref:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"film"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352447504810246229"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1672378983250000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Back to the Future"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;language:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;spoken:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;subtitles:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;language:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;spoken:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ref:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1672376421400000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;subtitles:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ref:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ref(Collection(&lt;/span&gt;&lt;span class="s2"&gt;"language"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"352444818516869204"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;ts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1672376421400000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"English"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Querying normalized data with user-defined primary keys
&lt;/h5&gt;

&lt;p&gt;In the above example, we had access to language references in the film document. Therefore, we could directly use Get() to dereference these references. We could have chosen user-defined primary keys instead of native Fauna references like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Academy Dinosaur&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;spoken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;subtitles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fauna is still able to retrieve the languages, but it would require an extra step with an index. For the sake of comparison, let’s implement the same query again with this use case. First, we need an index to retrieve the languages by id:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;CreateIndex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language_by_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;terms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main ingredients of &lt;a href="https://docs.fauna.com/fauna/current/api/fql/indexes?lang=javascript" rel="noopener noreferrer"&gt;indexes in Fauna&lt;/a&gt; are &lt;strong&gt;terms&lt;/strong&gt; and &lt;strong&gt;values&lt;/strong&gt;. Terms determine what the index matches on, while values determine what it returns (and in what order). Since indexes return values in Fauna, they are a mix of a view and an index as we know them in Postgres. In fact, we can significantly optimize our queries with indexes once we know our application’s data access patterns, as we’ll explain later. In this case, we’ll start in a generic fashion and only return the language reference from the index.&lt;/p&gt;

&lt;p&gt;We’ll call the index with the &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/match?lang=javascript" rel="noopener noreferrer"&gt;Match()&lt;/a&gt; function. As long as we only need the first result from Match(), we can call Get() on the match. We will see how to handle multiple results later on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
    &lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nc"&gt;Let&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;film&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filmRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="na"&gt;spokenLangId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="na"&gt;subLangId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subtitles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;film&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="na"&gt;spokenLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language_by_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spokenLangId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
            &lt;span class="na"&gt;subLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language_by_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subLangId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="c1"&gt;// and return the values however you want.&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you may wonder, should I use native Fauna references or user-defined keys? You can choose either. If you used custom keys or IDs in the Postgres implementation you are migrating from, you may have other business logic reasons to continue using them. If you use Fauna’s native references, you may simplify your code and retrieve data more efficiently (similar to what graph databases call &lt;a href="https://dmccreary.medium.com/how-to-explain-index-free-adjacency-to-your-manager-1a8e68ec664a" rel="noopener noreferrer"&gt;index-free-adjacency&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;And you can set your own custom IDs within Fauna's native references during document creation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;English&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;We covered a lot of ground here.  First, we outlined the key motivations why application developers are considering moving away from traditional relational databases like Postgres.  Even with Postgres’ feature maturity, scaling traditional database applications horizontally is still challenging, especially if the application is to handle very significant traffic loads. We covered key differences between Postgres and Fauna and provided a terminology mapping that should have demonstrated the equivalence of many shared concepts. &lt;/p&gt;

&lt;p&gt;We went through the process of creating a database, building a couple of collections, and inserting documents in those collections to illustrate a typical one-to-many database relation from one collection to another.  We covered using native Fauna references, as well as the alternatives of embedding and denormalizing the data, as well as using user-defined IDs, and how those decisions change how we build queries to retrieve the data in all those cases.  We used FQL to incrementally compose functions that look a lot like JavaScript, illustrating the deep integration that can be achieved in your application code without requiring an ORM or avoiding embedded SQL strings that can be prone to injections. &lt;/p&gt;

&lt;p&gt;This sets us up for part two, where we use a many-to-many relationship example to cover more modeling strategies and extend the idea of writing a domain-specific language with FQL. Finally, part three focuses on referential integrity as well as additional modeling, optimization, and migration ideas.  By the time you complete this journey, you should be armed with a solid foundational strategy to transition your Postgres-driven application. This strategy will provide you with enough guidance to have a scalable and performant resulting system from the beginning. It will also set you up with a composable and testable code base that will help you maintain your code leveraging modern application best practices. &lt;/p&gt;

&lt;h4&gt;
  
  
  About the author
&lt;/h4&gt;

&lt;p&gt;Luis Colon is a data scientist that focuses on modern database applications and best practices, as well as other serverless, cloud, and related technologies. He currently serves as a Senior Technology Evangelist at Fauna, Inc. You can reach him at &lt;a href="https://twitter.com/luiscolon1" rel="noopener noreferrer"&gt;@luiscolon1&lt;/a&gt; on &lt;a href="https://reddit.com/luiscolon1" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.reddit.com/user/luiscolon1" rel="noopener noreferrer"&gt;Reddit&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>softwaredevelopment</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>Side-by-side comparison of serverless databases</title>
      <dc:creator>Fauna</dc:creator>
      <pubDate>Thu, 29 Dec 2022 16:53:31 +0000</pubDate>
      <link>https://forem.com/fauna/side-by-side-comparison-of-serverless-databases-41hk</link>
      <guid>https://forem.com/fauna/side-by-side-comparison-of-serverless-databases-41hk</guid>
      <description>&lt;p&gt;Serverless databases make it easy to build and scale your application because they abstract away the underlying infrastructure and automatically scale to meet the need of your application. A serverless database lets you focus on your code without worrying about capacity planning, infrastructure maintenance, and server management.&lt;/p&gt;

&lt;p&gt;There are quite a few options for serverless databases, including established solutions like DynamoDB and newer offerings such as Mongo Atlas and CockroachDB serverless. This article compares commonly used serverless databases so you can make an informed decision when picking a new database for your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  MongoDB (Mongo Atlas)
&lt;/h2&gt;

&lt;p&gt;MongoDB is a widely used NoSQL database. MongoDB Atlas offers a provisioned managed service as well as a serverless offering. In this article we will compare the serverless offering. &lt;/p&gt;

&lt;p&gt;MongoDB Atlas offers fully managed serverless instances of MongoDB. With Mongo Atlas, you don’t have to manage any infrastructure by yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Connection over HTTP
&lt;/h3&gt;

&lt;p&gt;Mongo Atlas allows your application to connect to your database through an HTTP connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ Multi-region availability
&lt;/h3&gt;

&lt;p&gt;By default, MongoDB Atlas is deployed in a single region. However, MongoDB Atlas can automatically replicate data across multiple servers for improved reliability and availability. It is partially automated, and you’ll need prior knowledge of sharding and replication.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ Schema design (Schema-less, non-relational)
&lt;/h3&gt;

&lt;p&gt;MongoDB is flexible and suitable for both structured and unstructured data. Unlike a relational database, MongoDB doesn’t support foreign key joins. Because of this modeling, your data relationships can be tricky with Mongo. There are other ways to get around this problem in MongoDB. Review &lt;a href="https://stackoverflow.com/questions/31480088/join-two-collection-in-mongodb-using-node-js"&gt;this thread&lt;/a&gt; to learn more about data modeling in MongoDB.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ No cold starts
&lt;/h3&gt;

&lt;p&gt;If you have a large database then MongoDB Atlas clusters &lt;strong&gt;&lt;em&gt;can have a long cold start time&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️  ACID transactions
&lt;/h3&gt;

&lt;p&gt;Multi-document transactions are not enabled by default in MongoDB or MongoDB Atlas clusters. However, you can configure MongoDB to support multi-document ACID transactions based on your use case. &lt;/p&gt;

&lt;h2&gt;
  
  
  DynamoDB
&lt;/h2&gt;

&lt;p&gt;DynamoDB is a fully managed No-SQL database from Amazon. It supports key-value and document data structures. DynamoDB has a pay-as-you-go model, and it provides auto-scaling. &lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Connection over HTTP
&lt;/h3&gt;

&lt;p&gt;DynamoDB allows connection over HTTP.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ Multi-region availability
&lt;/h3&gt;

&lt;p&gt;You can setup multi-region availability with DynamoDB’s global tables feature. However, keep in mind there is significant configuration required to get it up and running properly. &lt;/p&gt;

&lt;p&gt;DynamoDB requires users to choose a partition key that determines how data is grouped and distributed among partitions. How you choose this key impacts DynamoDB’s scalability.  Having a thorough understanding of how your data will be accessed will be critical to selecting the most appropriate partitioning key and strategy. &lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ Schema design (Schema-less)
&lt;/h3&gt;

&lt;p&gt;DynamoDB is largely schema-less. Like many of its NoSQL siblings, DynamoDB lacks explicit support for relational data. It is designed with a denormalized schema in mind. Document sizes are also limited to 400kb in DynamoDB, forcing developers to denormalize the application data. &lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ No cold starts
&lt;/h3&gt;

&lt;p&gt;DynamoDB doesn’t have any cold start-related concerns. &lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ ACID transactions
&lt;/h3&gt;

&lt;p&gt;DynamoDB transactions are only ACID-compliant within a single region. DynamoDB does not support strongly consistent reads across regions.&lt;/p&gt;

&lt;p&gt;Follow this article for a detailed comparison of &lt;a href="https://fauna.com/blog/compare-fauna-vs-dynamodb"&gt;Fauna and DynamoDB&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  CockroachDB
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Like Mongo here we are focusing on the Serverless offering of the CockroachDB not the provisioned managed service since provisioned service doesn’t offer pay per usage.&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;CockroachDB is a distributed SQL database system. It is based on the idea of a "cockroach cluster," a group of nodes that work together to provide fault tolerance and high availability. Each node in a CockroachDB cluster can serve read and write requests, and the cluster can automatically recover from failures and distribute data evenly across the nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Connection over HTTP
&lt;/h3&gt;

&lt;p&gt;CockroachDB supports connection over HTTP. &lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Multi-region availability
&lt;/h3&gt;

&lt;p&gt;CockroachDB provides out-of-box multi-region availability without further configuration. &lt;/p&gt;

&lt;h3&gt;
  
  
  ⚠️ Schema design (SQL )
&lt;/h3&gt;

&lt;p&gt;CockroachDB has a Dynamic schema. It is relational and supports SQL. Since cockroach is based on traditional RDBMS it may take a lot of work to evolve unstructured data as your application grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❌ No cold starts
&lt;/h3&gt;

&lt;p&gt;For large amounts of datasets CockroachDB clusters may experience cold starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ ACID transactions
&lt;/h3&gt;

&lt;p&gt;CockroachDB fully supports strong consistency and ACID transactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fauna
&lt;/h2&gt;

&lt;p&gt;Fauna is a serverless database that combines the flexibility of NoSQL with the relational querying capabilities and consistency of SQL. You get the best of both worlds when using Fauna. It is fully managed, auto-scales, and does not require infrastructure management.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Connection over HTTP
&lt;/h3&gt;

&lt;p&gt;Fauna allows your applications to connect to the database over HTTP. You can use a Fauna driver or Fauna's GraphQL interface to communicate with the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Multi-region availability
&lt;/h3&gt;

&lt;p&gt;Fauna provides multi-region availability out of the box; it will auto-replicate your data across servers. It is distributed by default within a geographic region or across the globe. You always get strong consistency among region groups. Fauna is designed to keep the data closest to your users, improving reliability and availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Schema design (Document-relational)
&lt;/h3&gt;

&lt;p&gt;Fauna follows a &lt;a href="https://docs.fauna.com/fauna/current/learn/introduction/document_relational"&gt;document-relational&lt;/a&gt; database model. It &lt;strong&gt;combines the flexibility and familiarity of JSON documents with the relationships and querying power of a traditional relational database.&lt;/strong&gt; &lt;br&gt;
In short, you get the best of both SQL and NoSQL worlds with Fauna. Because of the flexible nature of the Fauna database, it is effortless to scale and evolve your data schema as your application grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ No cold starts
&lt;/h3&gt;

&lt;p&gt;Fauna has zero cold starts. &lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ ACID transactions
&lt;/h3&gt;

&lt;p&gt;One of the features of Fauna that has generated the most excitement is its strongly consistent distributed ACID transaction engine. Fauna provides strong consistency of data globally through an implementation of the &lt;a href="https://fauna.com/blog/distributed-consistency-at-scale-spanner-vs-calvin"&gt;Calvin&lt;/a&gt; protocol.&lt;/p&gt;

&lt;p&gt;Below you’ll find a visual comparison of all these serverless database offerings.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Mongo Atlas&lt;/th&gt;
&lt;th&gt;DynamoDB&lt;/th&gt;
&lt;th&gt;CockroachDB&lt;/th&gt;
&lt;th&gt;Fauna&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connection of HTTP&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-region availability&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No cold starts&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ACID transaction&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexible schema design&lt;/td&gt;
&lt;td&gt;⚠️ (NoSQL only)&lt;/td&gt;
&lt;td&gt;⚠️ (NoSQL only)&lt;/td&gt;
&lt;td&gt;⚠️ (SQL only)&lt;/td&gt;
&lt;td&gt;✅ (Document-relational)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are considering Fauna, create a &lt;a href="https://dashboard.fauna.com/"&gt;free account&lt;/a&gt; (no credit card required) and give it a go. If you have questions, you can reach out in the Fauna &lt;a href="https://discord.gg/NHwJFdG2B2"&gt;Discord channel&lt;/a&gt; or Fauna &lt;a href="https://forums.fauna.com/c/help-general"&gt;community forum&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>database</category>
      <category>fauna</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Implementing Fauna as infrastructure as code with Serverless Framework</title>
      <dc:creator>Fauna</dc:creator>
      <pubDate>Thu, 27 Oct 2022 17:26:24 +0000</pubDate>
      <link>https://forem.com/fauna/implementing-fauna-as-infrastructure-as-code-with-serverless-framework-3m99</link>
      <guid>https://forem.com/fauna/implementing-fauna-as-infrastructure-as-code-with-serverless-framework-3m99</guid>
      <description>&lt;p&gt;This article demonstrates how to use Fauna as infrastructure as code (IaC) in your application using the Serverless Framework, one of the most popular tools for managing infrastructure as code. Fauna has a dedicated &lt;a href="https://www.npmjs.com/package/@fauna-labs/serverless-fauna#installation"&gt;plugin&lt;/a&gt; for the Serverless Framework that gives you complete control to manage your Fauna resources. You can integrate it into your test and CI/CD pipelines to keep your databases in sync across multiple environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of IaC
&lt;/h2&gt;

&lt;p&gt;Before we dive deep into implementing Fauna as IaC, let's discuss why you might want to integrate IaC.&lt;/p&gt;

&lt;p&gt;There are three main benefits of IaC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decreased risks:&lt;/strong&gt; Provisioning all of your infrastructures manually can be risky, especially if you have multiple dependencies among services. Complex deployment is prone to human errors. When you automate the process with IaC, you reduce these. Your infrastructure also becomes testable, and you can spin up multiple environments (exact replicas of production).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient software development lifecycle:&lt;/strong&gt;  With IaC, infrastructure provisioning becomes more reliable and consistent. Developers get complete control of the infrastructure through code. Developers can script once and use that code multiple times, saving time and effort while keeping full control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-documenting and reduced administration:&lt;/strong&gt; IaC is self-documenting. And it reduces administrative overhead, allowing your engineering efforts to be focused on new feature development.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting started with the Fauna Serverless Framework plugin
&lt;/h2&gt;

&lt;p&gt;Install the Serverless Framework plugin with the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @fauna-labs/serverless-fauna &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or using yarn&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add @fauna-labs/serverless-fauna
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your &lt;code&gt;serverless.yml&lt;/code&gt; file and add the following code to add Fauna to your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@fauna-labs/serverless-fauna"&lt;/span&gt;
&lt;span class="na"&gt;fauna&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${env:FAUNA_ROOT_KEY}&lt;/span&gt;
    &lt;span class="c1"&gt;# domain: db.fauna.com&lt;/span&gt;
    &lt;span class="c1"&gt;# port: 433&lt;/span&gt;
    &lt;span class="c1"&gt;# scheme: https&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the domain is set to &lt;code&gt;[db.fauna.com](http://db.fauna.com)&lt;/code&gt;. You can create new collections by adding the collection name under the &lt;code&gt;collections&lt;/code&gt; field as demonstrated in the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;fauna&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${env:FAUNA_ROOT_KEY}&lt;/span&gt;
    &lt;span class="c1"&gt;# domain: db.fauna.com&lt;/span&gt;
    &lt;span class="c1"&gt;# port: 433&lt;/span&gt;
    &lt;span class="c1"&gt;# scheme: https&lt;/span&gt;
  &lt;span class="na"&gt;collections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Movies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Movies&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;some_data_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;some_data_value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The collection configuration accepts the same configuration as &lt;a href="https://docs.fauna.com/fauna/current/api/fql/functions/createcollection?lang=javascript#param_object"&gt;CreateCollection&lt;/a&gt; query. &lt;/p&gt;

&lt;p&gt;Similarly, you can add functions and indexes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;fauna&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${env:FAUNA_ROOT_KEY}&lt;/span&gt;
    &lt;span class="c1"&gt;# domain: db.fauna.com&lt;/span&gt;
    &lt;span class="c1"&gt;# port: 433&lt;/span&gt;
    &lt;span class="c1"&gt;# scheme: https&lt;/span&gt;
  &lt;span class="na"&gt;collections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Movies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Movies&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;some_data_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;some_data_value&lt;/span&gt;

  &lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;double&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;double&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./double.fql)}&lt;/span&gt;

  &lt;span class="na"&gt;indexes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;movies_by_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;movies_by_type&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:fauna.collections.Movies.name}&lt;/span&gt;
      &lt;span class="na"&gt;terms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;data.type&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can review the &lt;a href="https://www.npmjs.com/package/@fauna-labs/serverless-fauna#installation"&gt;documentation&lt;/a&gt; for the Serverless Framework plugin to learn more about different functionalities and implementations. &lt;/p&gt;

&lt;p&gt;We have also created a hands-on tutorial on &lt;a href="https://fauna.com/blog/building-a-rest-api-with-aws-lambda-fauna-and-serverless-framework"&gt;building a REST API with Fauna, Serverless, and AWS Lambda&lt;/a&gt;. This tutorial will help you get up and running with a simple project with Fauna and Serverless Framework.&lt;/p&gt;

&lt;p&gt;If you are searching for something more comprehensive, we have also created a self-paced workshop that will guide you through building a real-world project with Fauna, Serverless Framework, and AWS services. You can find the workshop &lt;a href="https://aws.workshops.fauna.com/"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;&lt;a href="https://aws.workshops.fauna.com/"&gt;Fauna AWS Workshop ~ Building an event-driven app with AWS services and Fauna&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This hands-on guide walks you through building a real-world event-driven serverless application using AWS services (i.e., AWS Lambda, Step Functions, API Gateway) and Fauna. In this workshop, you build a vacation booking application (Similar to Kayak or Redtag deals).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Got questions? Reach out in our &lt;a href="https://discord.gg/NHwJFdG2B2"&gt;Discord channel&lt;/a&gt; or in our &lt;a href="https://forums.fauna.com/c/help-general"&gt;community forum&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>fauna</category>
      <category>tutorial</category>
      <category>aws</category>
    </item>
    <item>
      <title>Delivering personalized content with Netlify’s Next.js Advanced Middleware and Fauna</title>
      <dc:creator>Fauna</dc:creator>
      <pubDate>Wed, 26 Oct 2022 14:10:27 +0000</pubDate>
      <link>https://forem.com/fauna/delivering-personalized-content-with-netlifys-nextjs-advanced-middleware-and-fauna-1n0k</link>
      <guid>https://forem.com/fauna/delivering-personalized-content-with-netlifys-nextjs-advanced-middleware-and-fauna-1n0k</guid>
      <description>&lt;p&gt;It’s become a truism that the speed and performance of web applications, e-commerce sites, and websites are critical variables in converting visitors to paying customers. Modern consumers expect these assets to serve data quickly, accurately, and contextually. API-first platforms like Fauna and &lt;a href="https://www.netlify.com"&gt;Netlify&lt;/a&gt;, paired with other composable technologies designed for distributed workloads, drastically simplify the process of deploying applications that serve dynamic content at the edge with low latency, without complicated stitching or multi-team engineering efforts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serving globally distributed data in legacy architectures
&lt;/h2&gt;

&lt;p&gt;Historically, developers have been constrained in how they optimize the performance attributes and experience of their applications by the underlying infrastructure - typically centralized servers and databases. The emergence of &lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network"&gt;content delivery networks&lt;/a&gt; (CDNs) in the early 2000s enabled companies to host and distribute static assets to a globally distributed audience with low latency - however these CDNs were limited to hosting static content like images, text files, and HTML files. As these CDNs were globally distributed, the performance attributes of this static content was far superior to relying on a more traditional centralized model - a user accessing a static site in Shanghai would access that content from the CDN node in Shanghai, instead of being pushed to a data center across the county. With that said, the benefits of serving static content through a CDN wasn’t extended to dynamic content that could change over time and evolve; this category of content relies on compute and data services to transform the data based on context.&lt;/p&gt;

&lt;p&gt;In the case of a global or even regional application, relying on a centralized architecture to serve dynamic content can be suboptimal. Consider an e-commerce application with users visiting the site from Los Angeles and Toronto. In an ideal world, the application would serve content that’s unique to those users and may change depending on context - where the user is physically located (and the potential discounts or prompts subsequently served to the user’s location), or if the user came from a referring source, for example. This data is ephemeral and dynamic in nature, and unique to each independent user accessing the application. If a user in Los Angeles is being served data hosted in the US-East 1 data center in Virginia, the performance attributes will suffer as a result simply due to the physical distance between the user and the compute. Similar to static content with CDNs, we want to optimize for speed and performance by moving the processing elements as close to each respective user as possible. This means pushing the compute and data out to the edge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic personalization at the edge
&lt;/h2&gt;

&lt;p&gt;Personalization allows companies to serve information that’s tailored for a particular customer based on a defined set of characteristics (most commonly geo-based). For example, if a visitor on an e-commerce site is based in Seattle, they may be served a discount on an item based on an inventory surplus in a local warehouse. Being able to serve this type of dynamic data, however, is not trivial. The ability to move the compute and data for dynamic content as close as possible to users (as demonstrated in CDNs) was until very recently impossible; this has changed with the emergence of platforms like Fauna and Netlify. &lt;/p&gt;

&lt;p&gt;With &lt;a href="https://www.netlify.com/blog/nextjs-advanced-middleware-better-runtime-that-extends-nextjs/"&gt;Next.js Advanced Middleware&lt;/a&gt; (powered by &lt;a href="https://docs.netlify.com/edge-functions/overview/"&gt;Netlify Edge Functions&lt;/a&gt;) and Fauna’s distributed-by-default &lt;a href="https://fauna.com/blog/what-is-a-document-relational-database?utm_source=Devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=DevTo_FaunaNetlify"&gt;document-relational&lt;/a&gt; database, we’re able to move servers and databases closer to user locations - similar to the shift we’ve witnessed with static assets served on CDNs, but now for dynamic content. Together, Fauna and Netlify enable a transformation in the application architecture for personalization at the edge: developers now have the option to host business logic wherever it’s most performant. &lt;/p&gt;

&lt;p&gt;When a user writes to or reads from a node, Netlify Edge Functions, the images/CSS files, and pieces of business logic are being grabbed from the closest possible compute node and corresponding data source node. Further, with the power of Fauna’s &lt;a href="https://docs.fauna.com/fauna/current/learn/understanding/user_defined_functions?utm_source=Devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=DevTo_FaunaNetlify"&gt;user-defined functions&lt;/a&gt; and advanced querying, you’re able to access a new mental model that allows you to make strategic decisions on where and how often work needs to be done; if you’re able to move the processing further back in the stack with Fauna, you can build it into the places that have the tightest relationships with the data and be optimized in ways that client-side JavaScript can’t be.&lt;/p&gt;

&lt;p&gt;While the middleware component of Next.js is germane to Next.js, out-of-the-box it is limited to redirects or rewrites (you can send users to another page, or proxy other content into the application and show users new content). Netlify has extended the middleware API to give access to the full request, which allows for full transformation and personalization - whether it’s location or referral based. With a proxy or a redirect, you’d need to develop a custom page for each redirect. The ability to do a direct transformation with Netlify ultimately makes the engineering far less cumbersome. Netlify provides a really good example of the power of page transformations &lt;a href="https://www.netlify.com/blog/rewrite-html-transform-page-props-in-nextjs/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Fauna + Netlify for edge personalization
&lt;/h2&gt;

&lt;p&gt;Fauna is delivered as a global API and is complementary to Netlify’s Edge Functions; ultimately, you don’t want to bloat your edge functions with code. Everything in the Fauna-Netlify architecture is server-side rendered, so it creates a faster experience by avoiding bloated client-side code that would flood the client CPU or the browser memory. You’re able to modify your code from being a large response down to the few lines you need to write to account for personalization, and it’s possible to do this in the edge function instead of the client-side without client-side impact to the user and without sacrificing performance. Until very recently, this type of architecture wasn’t possible to build, especially for small teams. With Fauna and Netlify, you can get up and running with a working solution within hours. &lt;/p&gt;

&lt;p&gt;Companies would historically need DevOps, frontend, backend, and database management teams to handle the orchestration of all of the elements associated with a global application. Now, a single full-stack developer can handle all of these elements and sketch out an application in a matter of hours that has global deployment, global database replication, and all of the front end and back end configured. Fauna’s auto-replication, distribution-by-default, and serverless attributes paired with Netlify’s edge compute make it possible. There’s no need to account for sharding, provisioning, or global replication - it’s all delivered out-of-the-box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Netlify Edge Functions + Fauna example and code walk-through
&lt;/h2&gt;

&lt;p&gt;To move out of the abstract and into a real-world example, we hosted a webinar with Netlify where we did a code walk-through of a basic marketing site pushed to the edge on Fauna and Netlify. Check out the &lt;a href="https://www.youtube.com/watch?v=X5uesJKkbh8"&gt;accompanying webinar&lt;/a&gt; and start digging into the code in the &lt;a href="https://github.com/Shadid12/netlify-edge"&gt;repo&lt;/a&gt; to learn how to build the functionality with just a few lines of code. You’ll see that in this example, one user is making a request to the site from Toronto, Canada, and another from Portland, Oregon. When each respective user makes a request, they hit the compute node closest to their respective locations and each is served a unique page. Meanwhile, the request is also directed to the nearest Fauna replica to read and serve the data. In this example, the read is modified at the edge and as close as possible to the user - which wouldn’t be possible with a regionally hosted database or server. Both the compute and data is at the edge - which ultimately reduces latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Fauna and Netlify unlock the ability to optimize for the most performant architectural decision based on the use case a team might be trying to solve, instead of being limited to whatever your legacy infrastructure may dictate.&lt;/p&gt;

&lt;p&gt;Are you ready to get started?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://app.fauna.com/sign-up?utm_source=Devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=DevTo_FaunaNetlify"&gt;Sign up for a free Fauna account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Grab your &lt;a href="https://dashboard.fauna.com/db/keys?utm_source=Devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=DevTo_FaunaNetlify"&gt;Fauna API key&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;a href="https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-faunadb-example"&gt;Deploy to Netlify button&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Have any questions or want to engage with the Fauna and Netlify communities? Reach out in the Fauna &lt;a href="https://discord.gg/NHwJFdG2B2"&gt;Discord channel&lt;/a&gt; or Fauna &lt;a href="https://forums.fauna.com/c/help-general?utm_source=Devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=DevTo_FaunaNetlify"&gt;community forum&lt;/a&gt;, and also check out the &lt;a href="https://answers.netlify.com"&gt;Netlify Community Forums&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>netlify</category>
      <category>fauna</category>
      <category>database</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Transfer data in Fauna to your analytics tool using Airbyte</title>
      <dc:creator>Fauna</dc:creator>
      <pubDate>Tue, 25 Oct 2022 21:48:01 +0000</pubDate>
      <link>https://forem.com/fauna/transfer-data-in-fauna-to-your-analytics-tool-using-airbyte-3g03</link>
      <guid>https://forem.com/fauna/transfer-data-in-fauna-to-your-analytics-tool-using-airbyte-3g03</guid>
      <description>&lt;p&gt;We are excited to introduce Fauna’s new &lt;a href="https://airbyte.com"&gt;Airbyte&lt;/a&gt; open source &lt;a href="https://docs.airbyte.com/integrations/sources/fauna/"&gt;connector&lt;/a&gt;. This connector lets you replicate Fauna data into your data warehouses, lakes, and analytical databases, such as Snowflake, Redshift, S3, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Airbyte
&lt;/h3&gt;

&lt;p&gt;With the proliferation of applications and data sources, companies are often required to build custom connectors for data transfer across their architectures. Most of these ETL (extract, transform, and load) tools require maintaining and updating the connectors as requirements change over time. Airbyte is an open source data pipeline platform that eliminates this burden by offering a robust connector ecosystem that can scale without having to maintain the connector itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Fauna
&lt;/h3&gt;

&lt;p&gt;Fauna is a distributed &lt;a href="https://fauna.com/blog/what-is-a-document-relational-database"&gt;document-relational database&lt;/a&gt; delivered as a cloud API. Developers choose Fauna’s document-relational model because it combines the flexibility of NoSQL databases with the relational querying and ACID capabilities of SQL databases. This model is delivered as an API so you can focus on building features and not to worry about any operations or infrastructure management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Fauna + Airbyte
&lt;/h3&gt;

&lt;p&gt;Fauna and Airbyte both enable improved productivity and developer experience - together, the connector will allow developers to port and migrate transactional data in Fauna to your choice of analytical tools to drive business insights.&lt;br&gt;
Continue reading for a guide on how to configure the Fauna &lt;em&gt;source&lt;/em&gt; connector to transfer your database to one of the data analytics or warehousing &lt;a href="https://airbyte.com/connectors?connector-type=Destinations"&gt;destination connectors&lt;/a&gt; supported by &lt;a href="https://airbyte.com/"&gt;Airbyte&lt;/a&gt;.&lt;br&gt;
The Fauna source supports the following ways to export your data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Full refresh append sync mode&lt;/em&gt; copies all of your data to the destination, without deleting existing data.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Full refresh overwrite sync mode&lt;/em&gt; copies the whole stream and replaces data in the destination by overwriting it.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Incremental append sync mode&lt;/em&gt; periodically transfers new, changed, or deleted data to the destination.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Incremental deduped history sync mode&lt;/em&gt; copies new records from stream and appends data in the destination, while providing a de-duplicated view mirroring the state of the stream in the source&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You need a destination database account and need to set up the &lt;a href="https://www.getdbt.com/"&gt;Data Build Tool&lt;/a&gt; (dbt™) to transform fields in your documents to columns in your destination. You also need to install Docker.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a destination database account
&lt;/h3&gt;

&lt;p&gt;If you do not already have an account for the database associated with your destination connector, create an account and save the authentication credentials for setting up the destination connector to populate the destination database.&lt;/p&gt;
&lt;h3&gt;
  
  
  Set up dbt
&lt;/h3&gt;

&lt;p&gt;To access the fields in your Fauna source using SQL-style statements, create a dbt account and set up dbt as described in the Airbyte &lt;a href="https://docs.airbyte.com/operator-guides/transformation-and-normalization/transformations-with-dbt/"&gt;Transformations with dbt&lt;/a&gt; setup guide. The guide steps you through the setup for transforming the data between the source and destination, and connects you to the destination database.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install Docker
&lt;/h3&gt;

&lt;p&gt;The Fauna connector is an Airbyte Open Source integration, deployed as a Docker image. If you do not already have Docker installed, follow the &lt;a href="https://docs.docker.com/engine/install/"&gt;Install Docker Engine&lt;/a&gt; guide.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Set up the Fauna source
&lt;/h2&gt;

&lt;p&gt;Depending on your use case, set up one of the following sync modes for your collection.&lt;/p&gt;
&lt;h3&gt;
  
  
  Full refresh sync mode
&lt;/h3&gt;

&lt;p&gt;Follow these steps to fully sync the source and destination database.&lt;/p&gt;

&lt;p&gt;1- Use the &lt;a href="https://dashboard.fauna.com/"&gt;Fauna Dashboard&lt;/a&gt; or &lt;code&gt;fauna-shell&lt;/code&gt; shell to create a role that can read the collection to be exported. The Fauna Source needs access to the Collections resource so that it can find which collections are readable. This does not give it access to all the collections, just the names of all the collections. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateRole({
  name: "airbyte-readonly",
  privileges: [{
    resource: Collection("COLLECTION_NAME"),
    actions: { read: true }
  }],
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;COLLECTION_NAME&lt;/code&gt; with the collection name for this connector.&lt;/p&gt;

&lt;p&gt;2- Create a secret that has the permissions associated with the role, using the &lt;code&gt;name&lt;/code&gt; of the role you created. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateKey({
  name: "airbyte-readonly",
  role: Role("airbyte-readonly"),
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  ref: Key("341909050919747665"),
  ts: 1662328730450000,
  role: Role("airbyte-readonly"),
  secret: "fnAEjXudojkeRWaz5lxL2wWuqHd8k690edbKNYZz",
  hashed_secret: "$2a$05$TGr5F3JzriWbRUXlKMlykerq1nnYzEUr4euwrbrLUcWgLhvWmnW6S"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the returned &lt;code&gt;secret&lt;/code&gt;, otherwise, you need to create a new key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental append sync mode
&lt;/h3&gt;

&lt;p&gt;Use incremental sync mode to periodically sync the source and destination, updating only new and changed data.&lt;/p&gt;

&lt;p&gt;Follow these steps to set up incremental sync.&lt;/p&gt;

&lt;p&gt;1- Use the &lt;a href="https://dashboard.fauna.com/"&gt;Fauna Dashboard&lt;/a&gt; or &lt;code&gt;fauna-shell&lt;/code&gt; to create an index, which lets the connector do incremental syncs. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateIndex({
  name: "INDEX_NAME",
  source: Collection("COLLECTION_NAME"),
  terms: [],
  values: [
    { "field": "ts" },
    { "field": "ref" }
  ]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;INDEX_NAME&lt;/code&gt; with the name you configured for the Incremental Sync Index. Replace &lt;code&gt;COLLECTION_NAME&lt;/code&gt; with the name of the collection configured for this connector.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|Index values|Description|
| --- | ----------- |
|`ts`| Last modified timestamp.|
|`ref`|Unique document identifier.|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;2- Create a role that can read the collection and index, and can access index metadata to validate the index settings. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateRole({
  name: "airbyte-readonly",
  privileges: [
    {
      resource: Collection("COLLECTION_NAME"),
      actions: { read: true }
    },
    {
      resource: Index("INDEX_NAME"),
      actions: { read: true }
    },
    {
      resource: Indexes(),
      actions: { read: true }
    }
  ],
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;COLLECTION_NAME&lt;/code&gt; with the name of the collection configured for this connector. Replace &lt;code&gt;INDEX_NAME&lt;/code&gt; with the name that you configured for the Incremental Sync Index.&lt;/p&gt;

&lt;p&gt;3- Create a secret key that has the permissions associated with the role, using the &lt;code&gt;name&lt;/code&gt; of the role you created. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CreateKey({
  name: "airbyte-readonly",
  role: Role("airbyte-readonly"),
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  ref: Key("341909050919747665"),
  ts: 1662328730450000,
  role: Role("airbyte-readonly"),
  secret: "fnAEjXudojkeRWaz5lxL2wWuqHd8k690edbKNYZz",
  hashed_secret: "$2a$05$TGr5F3JzriWbRUXlKMlykerq1nnYzEUr4euwrbrLUcWgLhvWmnW6S"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the returned &lt;code&gt;secret&lt;/code&gt;. You need to enter the secret in step 2 of the &lt;a href="https://deploy-preview-1193--fauna-docs.netlify.app/fauna/current/build/integrations/airbyte#install-docker"&gt;Install Docker&lt;/a&gt; procedure. It is important to save the key, otherwise, you need to create a new key if you lose the provided secret.&lt;/p&gt;

&lt;p&gt;The Fauna source iterates through all indexes on the database. For each index it finds, the following conditions must be met for incremental sync:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The source must be able to &lt;code&gt;Get()&lt;/code&gt; the index, which means it needs read access to this index.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The source of the index must be a reference to the collection you are trying to sync&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The number of values must be two.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The number of terms must be zero.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The values must be equal to:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;field&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ref&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of the above conditions are checked in the order listed. If a check fails, it skips that index.&lt;/p&gt;

&lt;p&gt;If no indexes are found in the initial setup, incremental sync isn't available for the given collection. No error is emitted because it can't be determined whether or not you are expecting an index for that collection.&lt;/p&gt;

&lt;p&gt;If you find that the collection doesn't have incremental sync available, make sure that you followed all the setup steps, and that the source, terms, and values all match for your index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Deploy and launch Airbyte
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Refer to the &lt;a href="https://docs.airbyte.com/quickstart/deploy-airbyte"&gt;Deploy Airbyte&lt;/a&gt; instructions to install and deploy Airbyte. Enter the following commands to deploy the Airbyte server:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/airbytehq/airbyte.git
&lt;span class="nb"&gt;cd &lt;/span&gt;airbyte
docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the Airbyte banner displays, launch the Airbyte dashboard at &lt;code&gt;http://localhost:8000&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose the &lt;strong&gt;Connections&lt;/strong&gt; menu item to start setting up your data source.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Set up the Fauna source
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the Airbyte dashboard, click the &lt;strong&gt;+ New connection button&lt;/strong&gt;. If you previously set up a source, click the &lt;strong&gt;Use existing source button&lt;/strong&gt; to choose that source.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the &lt;strong&gt;Source type&lt;/strong&gt; dropdown, choose &lt;strong&gt;Fauna&lt;/strong&gt; and click the &lt;strong&gt;Set up source&lt;/strong&gt; button. This lists the configurable Fauna connector parameters. An in-app &lt;strong&gt;Setup Guide&lt;/strong&gt; in the right-side panel also gives detailed setup instructions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the following required parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enter a descriptive name for this connection. The &lt;em&gt;name&lt;/em&gt; is displayed in the &lt;strong&gt;Connections&lt;/strong&gt; window connections list.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Domain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enter the domain of the collection you want to export. See &lt;a href="https://deploy-preview-1193--fauna-docs.netlify.app/fauna/current/learn/understanding/region_groups"&gt;Region Groups&lt;/a&gt; for region domains.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Port&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enter the default port number: &lt;code&gt;443&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Scheme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enter the scheme used to connect to Fauna: &lt;code&gt;https&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Fauna Secret&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enter the saved Fauna secret that you use to authenticate with the database.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Page Size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The page size lets you control the memory size, which affects connector performance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Deletion Mode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The deletion mode lets you specify whether to ignore document deletions or flag documents as deleted, depending on your use case.&lt;br&gt; + Choose from the following options:&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Ignore&lt;/strong&gt; option ignores document deletions.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Deleted Field&lt;/strong&gt; option adds a date column that has the date when you deleted the document. This maintains document history while letting the destination reconstruct deletion events.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After setting up the source, click the &lt;strong&gt;Set up source&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;The "All connection tests passed!" message confirms successful connection to the Fauna source. This minimally confirms:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-   The secret is valid.

&lt;ul&gt;
&lt;li&gt;  The connector can list collections and indexes.
&lt;/li&gt;
&lt;/ul&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;


Step 4: Set up the destination
&lt;/h2&gt;


&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the &lt;strong&gt;New connection&lt;/strong&gt; window, choose a &lt;strong&gt;Destination&lt;/strong&gt; type and click the &lt;strong&gt;Set up destination&lt;/strong&gt; button. If you previously set up a destination, click the &lt;strong&gt;Use existing destination&lt;/strong&gt; button to select and use that destination. Otherwise, continue to set up a new destination.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Destination connector configuration parameters are unique to the destination. Populate the &lt;strong&gt;Set up the destination&lt;/strong&gt; fields according to the connector requirements, including authentication information if needed. A &lt;strong&gt;Setup Guide&lt;/strong&gt; is provided in the right-side panel with detailed setup instructions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you are done, click the &lt;strong&gt;Set up destination&lt;/strong&gt; button.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: Set up the connection
&lt;/h2&gt;

&lt;p&gt;Set up the connection to sync the source and destination.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Enter a descriptive name for the connection in the &lt;strong&gt;Name&lt;/strong&gt; field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose a &lt;strong&gt;Transfer &amp;gt; Replication&lt;/strong&gt; frequency, which is the data sync interval.&lt;/p&gt;

&lt;p&gt;You can choose the &lt;strong&gt;Manual&lt;/strong&gt; option to manually sync the data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Streams &amp;gt; Destination Namespace&lt;/strong&gt; field, choose a destination namespace where the data is stored. Options include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Mirror source structure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets the name in the destination database to the name used for the Fauna source.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Other&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Uses another naming option, such as prefixing the database name with a string.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optionally, enter a stream name prefix in the &lt;strong&gt;Streams &amp;gt; Destination Stream Prefix&lt;/strong&gt; field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Activate the streams you want to sync&lt;/strong&gt; section, click the &lt;code&gt;&amp;gt;&lt;/code&gt; arrow to expand the available fields:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Collection data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unique document identifier.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Data timestamp.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ttl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Time-to-live interval.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The document is deleted if it is not modified in the &lt;code&gt;ttl&lt;/code&gt; time interval. The default value is &lt;code&gt;null&lt;/code&gt; for not used. After document deletion, it is not displayed in temporal queries and the connector does not emit a &lt;code&gt;deleted_at&lt;/code&gt; row.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select &lt;code&gt;ref&lt;/code&gt; as the &lt;strong&gt;Primary key&lt;/strong&gt;. This uniquely identifies the document in the collection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose a &lt;strong&gt;Sync mode&lt;/strong&gt; as the source sync behavior, full or incremental.&lt;/p&gt;

&lt;p&gt;A new incremental sync gets the full database, the same as a full sync.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sync mode&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Incremental - Deduped history&lt;/td&gt;
&lt;td&gt;Sync new records from stream and append data in destination, also provides a de-duplicated view mirroring the state of the stream in the source.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full refresh - Overwrite&lt;/td&gt;
&lt;td&gt;Sync the whole stream and replace data in destination by overwriting it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incremental - Append&lt;/td&gt;
&lt;td&gt;Sync new records from stream and append data in destination.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full refresh - Append&lt;/td&gt;
&lt;td&gt;Sync the whole stream and append data in destination.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If fewer than four options are displayed, it indicates that the index is incorrectly set up. See &lt;a href="https://fauna.com/blog/transfer-data-in-fauna-to-your-analytics-tool-using-airbyte#step-1-set-up-the-fauna-source"&gt;Step 1: Set up the Fauna source&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose the Normalization and Transformation data format:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data format&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Raw data (JSON)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Put all the source data in a single column.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Normalized tabular data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Put the &lt;code&gt;ref&lt;/code&gt;, &lt;code&gt;ts&lt;/code&gt;, &lt;code&gt;ttl&lt;/code&gt;, and &lt;code&gt;data&lt;/code&gt; fields in separate columns.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;+ Add transformation&lt;/strong&gt; button to add the dbt transform.&lt;/p&gt;

&lt;p&gt;To extract the fields in the source &lt;code&gt;data&lt;/code&gt; column, you need to configure dbt to map source data to destination database columns. For example, the following SQL-based query extracts the &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;account_balance&lt;/code&gt;, and &lt;code&gt;credit_card/expires&lt;/code&gt; fields from the source &lt;code&gt;data&lt;/code&gt; column to populate three separate columns of the destination data:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;select&lt;/span&gt;
    &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;account_balance&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;
    &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;credit_card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;expires&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cc_expires&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;airbyte_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="k"&gt;output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click the &lt;strong&gt;Set up connection&lt;/strong&gt; button.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 6: Sync the data
&lt;/h2&gt;

&lt;p&gt;On the &lt;strong&gt;Connection&lt;/strong&gt; page for the connection you created, click the &lt;strong&gt;Sync now&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;The time to run a sync varies with the status displayed in &lt;strong&gt;Sync History&lt;/strong&gt;. When the sync completes, the status changes from &lt;strong&gt;Running&lt;/strong&gt; to &lt;strong&gt;Succeeded&lt;/strong&gt; and shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The number of bytes transferred.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The number of records emitted and committed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The sync duration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 7: Verify the integration
&lt;/h2&gt;

&lt;p&gt;To expand the sync log, click the &lt;code&gt;&amp;gt;&lt;/code&gt; arrow to the right of the displayed time. This gives you a detailed view of the sync events.&lt;/p&gt;

&lt;p&gt;Finally, verify successful database transfer by opening and viewing the destination database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Integrating Fauna with the  Airbyte open source solution arms developers building on Fauna with a powerful tool for gaining insights into the operational data living on Fauna. We’re excited to build on our partnership with Airbyte by working towards introducing an Airbyte Cloud connector. If you have any interest in a Fauna + Airbyte Cloud integration or questions about the open source connector, feel free to reachout to us and ask questions in our &lt;a href="https://forums.fauna.com/"&gt;forum&lt;/a&gt; or on our &lt;a href="https://discord.gg/NHwJFdG2B2"&gt;Discord&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>fauna</category>
      <category>analytics</category>
      <category>tutorial</category>
      <category>database</category>
    </item>
    <item>
      <title>Building an edge serverless GraphQL backend with Cloudflare Workers and Fauna</title>
      <dc:creator>Shadid Haque</dc:creator>
      <pubDate>Wed, 05 Oct 2022 13:41:04 +0000</pubDate>
      <link>https://forem.com/fauna/building-an-edge-serverless-graphql-backend-with-cloudflare-workers-and-fauna-1bp0</link>
      <guid>https://forem.com/fauna/building-an-edge-serverless-graphql-backend-with-cloudflare-workers-and-fauna-1bp0</guid>
      <description>&lt;p&gt;This tutorial will teach you how to build a serverless GraphQL service on the edge with Cloudflare Workers and Fauna — allowing you to take advantage of two edge serverless compatible technologies. Try the &lt;a href="https://edge-graphql.shadid.workers.dev/" rel="noopener noreferrer"&gt;live demo here&lt;/a&gt;. You can find the complete code for this demo &lt;a href="https://github.com/fauna-labs/edge-graphql-cf-fauna" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Before diving into the code, let’s explore what edge serverless is and why it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is edge serverless?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.stackpath.com/edge-academy/what-is-edge-serverless/" rel="noopener noreferrer"&gt;Edge serverless&lt;/a&gt; is an infrastructural evolution of cloud serverless in which the computing resources that deliver serverless functions are located geographically closer to the end user. &lt;/p&gt;

&lt;p&gt;Cloudflare Workers are, by default, edge serverless functions. They are globally distributed in a way that the end user always hits the nearest compute instance, lowering latency. &lt;/p&gt;

&lt;p&gt;There are three main benefits of building your GraphQL service on edge serverless:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't have to manage servers. Your application auto scales.&lt;/li&gt;
&lt;li&gt;You pay per usage for your infrastructure.&lt;/li&gt;
&lt;li&gt;Your app is faster. The computing resources that deliver serverless functions are located geographically closer to the end user which reduces latency for your application.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why use Fauna as the database?
&lt;/h2&gt;

&lt;p&gt;By default, Fauna is a serverless database with edge support. Like Cloudflare Workers, Fauna is distributed and the data gets replicated across different servers within a specified region group. When users request data, it always retrieves the data from the nearest geographical location reducing the latency. &lt;/p&gt;

&lt;p&gt;You get the best of your edge infrastructure when your compute and database are both edge serverless compatible. In addition, Fauna is an easy-to-use database with zero administrative overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Make sure you have the following installed in your computer&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Node.js 16 or higher&lt;/li&gt;
&lt;li&gt;Cloudflare Wrangler CLI (&lt;a href="https://developers.cloudflare.com/workers/wrangler/get-started/" rel="noopener noreferrer"&gt;install instruction&lt;/a&gt;s)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Scaffolding a new Cloudflare Workers project
&lt;/h2&gt;

&lt;p&gt;Run the following code to scaffold a new Cloudflare Workers project with Wrangler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;wrangler init &amp;lt;my-awesome-project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI wizard will walk you through some configuration questions and bootstrap your application. When it asks you &lt;code&gt;Would you like to create a Worker&lt;/code&gt; select &lt;code&gt;Yes&lt;/code&gt; and select &lt;code&gt;Fetch handler&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;src/index.ts&lt;/code&gt; file. You will see some code that reads as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;wrangler dev&lt;/code&gt; and visit &lt;a href="http://0.0.0.0:8787/" rel="noopener noreferrer"&gt;http://0.0.0.0:8787/&lt;/a&gt;. It should display “Hello World!”. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a GraphQL server in Cloudflare Workers
&lt;/h2&gt;

&lt;p&gt;Run the following command to install all the dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm i @graphql-yoga/common faunadb &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, delete everything from &lt;code&gt;index.ts&lt;/code&gt; file and add the following code. Here you are creating a simple GraphQL server with &lt;code&gt;@graphql-yoga&lt;/code&gt; library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@graphql-yoga/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* GraphQL */&lt;/span&gt; &lt;span class="s2"&gt;`
      type Query {
        hello(msg: String): String
      }
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resolvers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;wrangler dev&lt;/code&gt; and visit &lt;a href="http://0.0.0.0:8787/" rel="noopener noreferrer"&gt;http://0.0.0.0:8787/&lt;/a&gt; in your browser. In your browser, a GraphQL playground will open. &lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/115B1DTmabER1etcRKOuHL/3ea4ef42ba93b8da713cc6db4899d7c4/0_-_GraphQL_playground.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/115B1DTmabER1etcRKOuHL/3ea4ef42ba93b8da713cc6db4899d7c4/0_-_GraphQL_playground.png" alt="GraphQL playground"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make the following query in GraphQL playground to make sure everything is working as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"adwwd"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="err"&gt;":&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="err"&gt;":&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;adwwd&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s go ahead and replace the GraphQL schema with something more practical. We want CRUD (Create, Read, Update and Delete) operations in our GraphQL service. Make the following changes to the schema to add CRUD.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;createServer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'@graphql-yoga/common'&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;createServer(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GraphQL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;listPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mutation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;addPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;deletePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Boolean&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;updatePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Subscription&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;onPostChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PostInput&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;resolvers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;server.start()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have your schema ready. However, you cannot execute these queries and mutations since the resolvers are not yet implemented. &lt;/p&gt;

&lt;p&gt;Before we can implement the resolver functions let’s go ahead and set up our database. We are using Fauna as our database. &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Fauna database
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dashboard.fauna.com/accounts/register" rel="noopener noreferrer"&gt;Sign up for a free forever Fauna account&lt;/a&gt; and create a new database.  &lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/2ASEtb4lCWukXyOznVSs1e/6afd430c2c4b4a7cbd3ec42895f96a33/1_-_Create_database.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/2ASEtb4lCWukXyOznVSs1e/6afd430c2c4b4a7cbd3ec42895f96a33/1_-_Create_database.png" alt="Create database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new collection called &lt;code&gt;Post&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/skplUkcVWvoG4HTYyv8va/eef0f9198de6f1a19af36c6a97daed44/2_-_Create_a_new_collection.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/skplUkcVWvoG4HTYyv8va/eef0f9198de6f1a19af36c6a97daed44/2_-_Create_a_new_collection.png" alt="Create a new collection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/2tAuJOgY753rAUcziPKp67/186f567ee960406ca78a26e37f5d8575/3_-_New_collection_name.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/2tAuJOgY753rAUcziPKp67/186f567ee960406ca78a26e37f5d8575/3_-_New_collection_name.png" alt="New collection name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, go over to the Security tab and create a new server secret for your database.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/4XaueLYkck4PSRgrUMs3av/215bf6f74a785de6ab633f8e38eb860e/4_-_Create_security_key.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/4XaueLYkck4PSRgrUMs3av/215bf6f74a785de6ab633f8e38eb860e/4_-_Create_security_key.png" alt="Create security key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/3EqABa2BtFoGUrnAAy0srn/e110c628d7231ae28358d77d8ad43e7d/5_-_Save_new_key.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/3EqABa2BtFoGUrnAAy0srn/e110c628d7231ae28358d77d8ad43e7d/5_-_Save_new_key.png" alt="Save new key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the generated database secret. &lt;strong&gt;Make sure you do not reveal this secret in your version control.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Back in the code, add the Fauna database key and domain in your &lt;code&gt;wrangler.toml&lt;/code&gt; file as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# wrangler.toml&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"edge-graphql"&lt;/span&gt;
&lt;span class="py"&gt;main&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"src/index.ts"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2022-09-23"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_flags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"streams_enable_constructors"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="py"&gt;node_compat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="nn"&gt;[vars]&lt;/span&gt;
&lt;span class="py"&gt;FAUNA_SECRET&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"fnAxxx...."&lt;/span&gt;
&lt;span class="py"&gt;FAUNA_DOMAIN&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"db.us.fauna.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a new file &lt;code&gt;src/db.ts&lt;/code&gt; and add the following code. In the following code snippet, you initialize the Fauna database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;faunadb&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;faunadb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;faunadb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FAUNA_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FAUNA_SECRET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;faunadb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FAUNA_DOMAIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FAUNA_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementing resolvers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add post (Mutation)
&lt;/h3&gt;

&lt;p&gt;First, you need to enable &lt;em&gt;node_compat&lt;/em&gt; mode for Cloudflare Workers since you will use modular JavaScript. Go to &lt;code&gt;wrangler.toml&lt;/code&gt; file and add the following line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ggop"&lt;/span&gt;
&lt;span class="py"&gt;main&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"src/index.ts"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2022-09-25"&lt;/span&gt;
&lt;span class="py"&gt;node_compat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="nn"&gt;[vars]&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;code&gt;src/index&lt;/code&gt; file, under resolvers field, add a new resolver function &lt;code&gt;addPost&lt;/code&gt; as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@graphql-yoga/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* GraphQL */&lt;/span&gt; &lt;span class="s2"&gt;`
      ...
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resolvers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;Mutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;addPost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You use the Fauna driver functions in the resolver to add a new post to the database. If you are new to Fauna, the documentation for &lt;a href="https://docs.fauna.com/fauna/current/learn/tutorials/fql/crud?lang=javascript" rel="noopener noreferrer"&gt;how to perform CRUD operations in Fauna&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;wrangler dev&lt;/code&gt; in your terminal. Visit &lt;a href="http://localhost:8787/" rel="noopener noreferrer"&gt;http://localhost:8787/&lt;/a&gt; to interact with your GraphQL playground. Create a new GraphQL mutation to add post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;mutation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AddPost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;addPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New Tittle"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Another Post"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="c"&gt;# Result &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="err"&gt;":&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;addPost&lt;/span&gt;&lt;span class="err"&gt;":&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="err"&gt;":&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"343885948385230924"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="err"&gt;":&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tittle&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="err"&gt;":&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Another&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go back to the Fauna dashboard and notice that under &lt;code&gt;Post&lt;/code&gt; collection a new record is generated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update and delete post (Mutation)
&lt;/h3&gt;

&lt;p&gt;Similarly, you can create update and delete resolvers to update and delete posts. Make the following changes to your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* GraphQL */&lt;/span&gt; &lt;span class="s2"&gt;`
      // ...
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resolvers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;Mutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;addPost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;deletePost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;updatePost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;updatePost&lt;/code&gt; and &lt;code&gt;deletePost&lt;/code&gt; mutation from your GraphQL playground to make sure everything is working as expected. &lt;/p&gt;

&lt;h3&gt;
  
  
  Get post and post list (Query)
&lt;/h3&gt;

&lt;p&gt;Next, add the &lt;code&gt;listPost&lt;/code&gt; and &lt;code&gt;getPost&lt;/code&gt; resolver functions under Query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@graphql-yoga/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* GraphQL */&lt;/span&gt; &lt;span class="s2"&gt;`
        //...
      `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;resolvers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;getPost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;listPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))),&lt;/span&gt;
                &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({...&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;Mutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the GraphQL playground try out the queries and make sure that everything is working as expected. &lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing subscription
&lt;/h2&gt;

&lt;p&gt;Cloudflare Workers support &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Streams_API" rel="noopener noreferrer"&gt;Streams API&lt;/a&gt;. Using this Streams API, you can send &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events" rel="noopener noreferrer"&gt;server-sent events&lt;/a&gt; (SSE) to your client. A client subscribes to the server in real-time through SSE. &lt;/p&gt;

&lt;p&gt;Fauna also has a streaming API to listen to real-time database changes. Combining these two allows you to implement a complete &lt;strong&gt;&lt;em&gt;serverless GraphQL subscription solution on edge.&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Keep in mind that there is &lt;strong&gt;no WebSocket involved&lt;/strong&gt; in this implementation.&lt;/p&gt;

&lt;p&gt;Add a new subscription function called &lt;code&gt;onPostChange&lt;/code&gt; to your resolvers field, as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* GraphQL */&lt;/span&gt; &lt;span class="s2"&gt;`
    `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;resolvers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;Mutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;onPostChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;currentSnap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;newVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;faunaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docRef&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;snapshot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;currentSnap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; 
            &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;newVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;subscriptionTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Terminate Subscription after 1000 seconds&lt;/span&gt;

            &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subscriptionTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
              &lt;span class="nx"&gt;subscriptionTime&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newVersion&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;newVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;currentSnap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;currentSnap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newVersion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;subscriptionTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Reset Subscription Time&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;onPostChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;newVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;onPostChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Disconnected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous code snippet you use Fauna’s document streaming feature to subscribe to a database record. Whenever the record is updated or deleted, the Fauna client will be notified in real time. You can then emit this event to your GraphQL resolver. &lt;/p&gt;

&lt;p&gt;Notice that this is an SSE implementation. This is why we have an iterator function that keeps track of a heartbeat (every two seconds) in the server. After five minutes you close the connection. &lt;/p&gt;

&lt;p&gt;It is very important to close the connection to Fauna stream after a period of time, otherwise, you will be charged for the running connection. &lt;/p&gt;

&lt;p&gt;Subscriptions can also be done through a Pub/Sub implementation. That way, you don’t have to consistently listen to database changes. Depending on your use case, a Pub/Sub layer might be more economical. However, &lt;a href="https://developers.cloudflare.com/pub-sub/" rel="noopener noreferrer"&gt;Cloudflare Pub/Sub&lt;/a&gt; is currently in closed beta. Once this feature is generally available, we will create another tutorial using Cloudflare Pub/Sub and Fauna. &lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go from here
&lt;/h2&gt;

&lt;p&gt;Got questions about Fauna, Cloudflare, serverless, or GraphQL? Feel free reach out to us and ask  questions in our &lt;a href="https://forums.fauna.com/" rel="noopener noreferrer"&gt;forum&lt;/a&gt; or on our &lt;a href="https://discord.gg/NHwJFdG2B2" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>graphql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building scalable solutions with Apollo Federation and Fauna</title>
      <dc:creator>Shadid Haque</dc:creator>
      <pubDate>Wed, 24 Aug 2022 16:21:00 +0000</pubDate>
      <link>https://forem.com/fauna/building-scalable-solutions-with-apollo-federation-2b0j</link>
      <guid>https://forem.com/fauna/building-scalable-solutions-with-apollo-federation-2b0j</guid>
      <description>&lt;p&gt;This article explains how you can reduce complexity, develop features faster, and make your engineering teams more efficient using &lt;a href="https://www.apollographql.com/blog/backend/federation/introduction-to-apollo-federation/" rel="noopener noreferrer"&gt;Apollo Federation&lt;/a&gt; and Fauna.&lt;/p&gt;

&lt;p&gt;Apollo Federation is designed for implementing GraphQL in a microservice architecture. On the other hand, Fauna is a distributed serverless document-relational database delivered as an API. Fauna's native GraphQL API allows engineers to directly integrate it as a subgraph in Apollo Federation or use it as a database for individual microservices.&lt;/p&gt;

&lt;p&gt;Apollo Federation combined with Fauna improves developer experience and increases productivity, solving the problem of schema stitching and addressing pain points such as coordination, separation of concerns, and brittle gateway code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges of modern application development and how to solve it
&lt;/h2&gt;

&lt;p&gt;Many organizations find it challenging to deliver products and features with velocity. More and more organizations are investing massive amounts of resources to make their infrastructure resilient and flexible. Yet, scattered microservices, versioned REST endpoints, and complex database management systems result in slow delivery of features/product development.&lt;/p&gt;

&lt;p&gt;GraphQL revolutionized the way organizations build applications. GraphQL, open-sourced by Facebook in 2015, helps engineering teams integrate their array of REST APIs and microservices into a unified schema that frontend developers can query, fetching only the data required to power an experience while being agnostic to the data source. Traditional REST APIs lead to under or over-fetching data.&lt;/p&gt;

&lt;p&gt;Fast forward to 2022, and the complexity of modern APIs and applications has grown exponentially. Running everything through a single GraphQL server (read: monolith) with multiple teams rapidly contributing changes creates a bottleneck.&lt;/p&gt;

&lt;p&gt;What if there was a way for each microservice to have its own graph that could be seamlessly composed into a supergraph? Enter Apollo Federation. With &lt;a href="https://apollographql.com/docs/federation" rel="noopener noreferrer"&gt;Apollo Federation&lt;/a&gt;, you can build a declarative, modular GraphQL architecture.&lt;/p&gt;

&lt;p&gt;A supergraph is composed of smaller graphs called subgraphs, each with its own schema. Teams can evolve their subgraphs independently, and their changes will be automatically rolled into the overall supergraph, allowing them to deliver autonomously and incrementally.&lt;/p&gt;

&lt;p&gt;Your application data layer (database) is a critical part of your application architecture. Fauna is a database designed with modern applications and GraphQL architecture in mind. Fauna can seamlessly integrate as a subgraph in your Apollo Federation supergraph.&lt;/p&gt;

&lt;p&gt;Moreover, Fauna's custom GraphQL resolvers gives the engineers the ability to turn the database into a fully-fledged microservice. You can learn more about Fauna's GraphQL capabilities in the &lt;a href="https://docs.fauna.com/fauna/current/learn/quick_start/gql_quick_start" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Fauna is a database that gives you the ability to form your data from a declarative GraphQL schema while giving you the complete freedom to implement your resolver functions if you have to. The document-relation model of Fauna also makes it flexible for evolving applications. Fauna combines the simplicity of NoSQL, without sacrificing the ability to model complex relationships.&lt;/p&gt;

&lt;p&gt;Fauna’s flexibility and GraphQL native API combined with Apollo Federation allows engineers to build robust solutions faster with more flexibility and less code.&lt;/p&gt;

&lt;p&gt;Let’s walk through a few different approaches for how to integrate Apollo Federation and Fauna, depending on your needs and existing architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Microservices and Fauna (Traditional subgraphs)
&lt;/h3&gt;

&lt;p&gt;Having a separate database for each of your microservices is a common practice. You can use the Fauna database as your data layer in each microservices. Your services can connect to Fauna with any of the supported drivers.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/nnjX87NhklE7yarqj1bxA/4bb182f44cc03184266a6d47c5c50924/image_1.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/nnjX87NhklE7yarqj1bxA/4bb182f44cc03184266a6d47c5c50924/image_1.png" alt="This is a traditional microservice-based architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a traditional microservice-based architecture. Each microservice is a subgraph in this case, and you compose these subgraphs into a supergraph using Apollo Federation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Fauna-hosted GraphQL endpoints as subgraphs
&lt;/h3&gt;

&lt;p&gt;Suppose your product is primarily frontend focused (Jamstack or serverless-native) and you are not ready to commit to multiple microservices yet but want separation of concerns in the data layer. In that case, this architecture pattern is for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/3zVpGvgbyrIdRcKZ0MhpnV/f347a15bd805238a1b4498584d5d82f7/image_2.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/3zVpGvgbyrIdRcKZ0MhpnV/f347a15bd805238a1b4498584d5d82f7/image_2.png" alt="Using Fauna-hosted GraphQL endpoints as subgraphs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this pattern, you will ideally have three Fauna databases. Each database has its GraphQL schema. Each of these schemas is then combined into a Federation supergraph.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid model
&lt;/h3&gt;

&lt;p&gt;In the hybrid model, you combine the two approaches discussed earlier. This is ideal when you are rapidly scaling your product and solutions.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/6ssucOnt6idcJ1FFxUH03/f85e81c8e0632a90099bf6e76fc4f57b/image_3.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/6ssucOnt6idcJ1FFxUH03/f85e81c8e0632a90099bf6e76fc4f57b/image_3.png" alt="Hybrid model"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with Fauna and Apollo Federation 2
&lt;/h2&gt;

&lt;p&gt;Let’s create a federated e-commerce solution using Apollo Federation and Fauna. In this example app, we will combine a Fauna GraphQL subgraph that includes information about shops and products with one from Apollo that provides locations.&lt;/p&gt;

&lt;p&gt;You can find the complete code in &lt;a href="https://github.com/fauna-labs/apollo-federation" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Fauna
&lt;/h3&gt;

&lt;p&gt;Head over to &lt;a href="https://dashboard.fauna.com/" rel="noopener noreferrer"&gt;dashboard.fauna.com&lt;/a&gt; and create a new database. Create a new GraphQL schema. You can use the following schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Shop {
  name: String!
  description: String!
  coverImg: String!
  products: [Product]! @relation
  ownerID: String!
}

type Product {
  name: String!
  description: String!
  price: Float!
  category: String!
  imageUrl: String
  shop: Shop! @relation
}

type Query {
  products: [Product]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload the schema to your Fauna database. Select the GraphQL option in your Fauna dashboard then select import schema.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/2tZqsKfBC00bxz3jfnSHai/d20b61e1829aacbc1ecf483d1ede3a50/image_4.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/2tZqsKfBC00bxz3jfnSHai/d20b61e1829aacbc1ecf483d1ede3a50/image_4.png" alt="Upload the schema to your Fauna database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you upload the schema your collections in your database will be generated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Records to Your Collection
&lt;/h3&gt;

&lt;p&gt;Next, create some records in Fauna using the GraphQL playground. Run the following mutation to create a new product.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation CreateProduct {
  createProduct(
   data: {
    name: "fender stratocaster",
    description: "The world's greatest electric guitar",
    price: 1255,
    imageUrl: "guitar.png",
    category: "Music",
  }
 ) {
   _id
   name
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a Shop by running the following mutation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation CreateShop {
  createShop(
   data: {
    ownerID: "1223302094",
    name: "Scarborough Music and Records",
    description: "some music shop",
    coverImg: "example-shop.png"
   }
  ) { _id }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrate Fauna and Apollo
&lt;/h3&gt;

&lt;p&gt;To integrate Fauna as a subgraph with Apollo Federation, you need the full GraphQL SDL from Fauna. You can download this from the Fauna GraphQL playground. Select schema from the playground and download the schema.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/1pziTENJ0ZGWc4UNqSgxGh/07711e3bd1bb75c3749996fbf46363ba/image_5.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/1pziTENJ0ZGWc4UNqSgxGh/07711e3bd1bb75c3749996fbf46363ba/image_5.png" alt="Integrate Fauna and Apollo 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/1iKSuah1LUSsyZnwx1p0c6/dceb36e8ee3f28cf19df2484196ce1d8/image_6.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/1iKSuah1LUSsyZnwx1p0c6/dceb36e8ee3f28cf19df2484196ce1d8/image_6.png" alt="Integrate Fauna and Apollo 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, navigate to security section and generate a new server key for your database.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/4tq6nKPBrq7vIrvDsxYXZs/3342e0e94f732e1a906fcaaf929f9d8c/image_7.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/4tq6nKPBrq7vIrvDsxYXZs/3342e0e94f732e1a906fcaaf929f9d8c/image_7.png" alt="New server key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/7AWiR4vJvkqgjKCoubSkYf/818e6b8e2b02f51ce4c2a236eb9134d4/image_8.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/7AWiR4vJvkqgjKCoubSkYf/818e6b8e2b02f51ce4c2a236eb9134d4/image_8.png" alt="Save new server key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up supergraph
&lt;/h3&gt;

&lt;p&gt;Create a new &lt;code&gt;supergraph-config.yaml&lt;/code&gt; file. This file will contain the supergraph specification as well as subgraphs url and schema. Add the following code to your &lt;code&gt;supergraph-config.yaml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;federation_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;subgraphs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fauna&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;routing_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://graphql.fauna.com/graphql`&lt;/span&gt;
   &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./fauna.graphql&lt;/span&gt;
 &lt;span class="na"&gt;locations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;routing_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://flyby-locations-sub.herokuapp.com/&lt;/span&gt;
   &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;subgraph_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://flyby-locations-sub.herokuapp.com/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are federating two subgraphs — one being Fauna and the other is a sample microservice from Apollo.&lt;/p&gt;

&lt;p&gt;Run the following command to generate the supergraph&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rover supergraph compose --config ./supergraph-config.yaml &amp;gt; supergraph.graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous command composes a supergraph schema from the specified subgraphs. The supergraph schema is saved in the &lt;code&gt;supegraph.graphql&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local composition service with Apollo Gateway and Federation
&lt;/h3&gt;

&lt;p&gt;Next, you create a local composition service. Create a new file called &lt;code&gt;index.js&lt;/code&gt; and add the following code. This service acts as the gateway to your supergraph.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apollo-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloGateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RemoteGraphQLDataSource&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@apollo/gateway&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supergraphSdl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./supergraph.graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthenticatedDataSource&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;RemoteGraphQLDataSource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;willSendRequest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloGateway&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;supergraphSdl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;buildService&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthenticatedDataSource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;gateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🚀 Gateway ready at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to install the required dependencies for this service. Run the following command to install the dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i apollo-server @apollo/gateway &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Query your federated subgraph
&lt;/h3&gt;

&lt;p&gt;Run the service with &lt;code&gt;node index.js&lt;/code&gt; command. Navigate to &lt;a href="http://localhost:4000/" rel="noopener noreferrer"&gt;http://localhost:4000/&lt;/a&gt; in your browser. It will open up &lt;a href="https://studio.apollographql.com/" rel="noopener noreferrer"&gt;Apollo Studio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You now have a federated graph up and running that uses Fauna as a subgraph. Run the following composed query to make sure everything is working correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query FindProductByID($findProductByIdId: ID!) {
  findProductByID(id: $findProductByIdId) {
    _id
    name
    description
  }
  locations {
    id
    name
  }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Variables field you will need to supply a product ID from your Fauna DB:&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/5jN09pVfwfNFVvFA4UMmBq/a943def012ee6e3b0f962c8a496adf9b/image_9.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/5jN09pVfwfNFVvFA4UMmBq/a943def012ee6e3b0f962c8a496adf9b/image_9.png" alt="ProductID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve supplied your variables, make sure you pass in the authorization header. Use the Fauna secret key as the token for our authorization header.Your authorization header should be the following format &lt;code&gt;Bearer fnAEukxxx&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/3EVUebCLdxkAAwDe7qIYst/8f16f7b852c73032b1a156b7cce9cc9b/image_10.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/3EVUebCLdxkAAwDe7qIYst/8f16f7b852c73032b1a156b7cce9cc9b/image_10.png" alt="Pass in the authorization header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The previous query returns a composed response from Fauna and locations microservice.&lt;/p&gt;

&lt;p&gt;If you’d like to continue exploring federation with the subgraphs we created above, you can find the code for this example in &lt;a href="https://github.com/fauna-labs/apollo-federation" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Combining Apollo Federation and Fauna allows engineers to be flexible, anticipate future API changes, and implement them easily without "&lt;em&gt;breaking changes"&lt;/em&gt;. In modern application development, engineering time is the most valuable resource. Apollo Federation and Fauna both focus on developer experience, helping engineers to be more productive and ship features faster at scale.&lt;/p&gt;

&lt;p&gt;Have questions about using Fauna with Apollo Federation? Join the &lt;a href="https://fauna.com/community" rel="noopener noreferrer"&gt;Fauna community&lt;/a&gt; channels and we would be happy to answer any questions you have. If you want to learn more about the &lt;a href="https://community.apollographql.com/" rel="noopener noreferrer"&gt;Apollo Community forum&lt;/a&gt;. For more reference architecture and code examples with Fauna and Apollo, follow fauna labs on &lt;a href="https://github.com/fauna-labs" rel="noopener noreferrer"&gt;github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>graphql</category>
      <category>database</category>
      <category>fauna</category>
    </item>
    <item>
      <title>Comparing databases for Vercel and Netlify</title>
      <dc:creator>Shadid Haque</dc:creator>
      <pubDate>Fri, 12 Aug 2022 20:24:12 +0000</pubDate>
      <link>https://forem.com/fauna/comparing-databases-for-vercel-and-netlify-34i1</link>
      <guid>https://forem.com/fauna/comparing-databases-for-vercel-and-netlify-34i1</guid>
      <description>&lt;p&gt;Vercel and Netlify make it easy for developers to build and ship full-stack serverless applications. Both platforms provide features such as serverless edge functions, CDN (content delivery network), build tools, analytics, etc. While building full-stack applications on these platforms, developers have quite a few options for their data layer (database). This article compares the databases commonly used with Vercel and Netlify, so you can make an informed decision when picking a new database for your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  PlanetScale
&lt;/h2&gt;

&lt;p&gt;PlanetScale is an easy to use MySQL-compatible serverless database. MySQL is easy to get up and running. However, you have to scale up your MySQL instances as your database grows. Database sharding is a common technique that is used to scale MySQL.&lt;/p&gt;

&lt;p&gt;Sharding is a scale-out technique in which database tables are partitioned and each partition is hosted on its own RDBMS server. In the case of MySQL, this means that each node is its own MySQL RDBMS, with its own set of data partitions.&lt;/p&gt;

&lt;p&gt;PlanetScale uses &lt;a href="https://vitess.io/docs/14.0/overview/scalability-philosophy/" rel="noopener noreferrer"&gt;Vitess&lt;/a&gt; sharding to scale up the databases. While Vitess makes it easier to administer database shards, PlanetScale doesn’t actually shard databases automatically, so this is something that needs to be engineered on your own. If you wish to scale your database in a distributed manner – either now or in the future – you need to take this limitation into consideration. &lt;/p&gt;

&lt;p&gt;Shards can be complicated to get right. You occasionally have to worry about splitting bits which is complicated. Joins across shards are not easily doable. If you need cross-shard joining, you probably need a data warehouse.&lt;/p&gt;

&lt;p&gt;At the moment, PlanetScale appears to provide limited functionality and has focused its key differentiator around its unique branching feature for schema migration. However, some core database features seem to be missing, such as support for foreign key constraints. It also does not have a GraphQL API, and does not have any streaming capabilities. &lt;/p&gt;

&lt;h3&gt;
  
  
  PlanetScale with edge architecture
&lt;/h3&gt;

&lt;p&gt;One of the primary appeals of Vercel and Netlify is that they have serverless edge support. Edge offering allows you to keep your serverless functions closer to your users.&lt;/p&gt;

&lt;p&gt;For instance, let's assume you have a Next.js application deployed on Vercel. A user from Spain tries to access your application. The application will then be served from the nearest location to Spain. Vercel distributes your application worldwide, so your users don't face the added latency.&lt;/p&gt;

&lt;p&gt;However, if your database is not distributed, then your edge functions will not be as performant. For instance, if your database server is located in Ney York, USA, and your compute function is in Lisbon, Portugal, it will add a significant delay. Ideally, you need a database that is also distributed globally to reduce latency.&lt;/p&gt;

&lt;p&gt;To learn more about edge vs serverless performance and what role databases play in the architecture refer to this &lt;a href="https://www.youtube.com/watch?v=yOP5-3_WFus&amp;amp;ab_channel=Fireship" rel="noopener noreferrer"&gt;video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since PlanetScale is not globally distributed, it might have some performance drawbacks. However, PlanetScale does offer multiple regions, and you can manually architect your application to fetch data from the nearest region.&lt;/p&gt;

&lt;p&gt;If you are building an application that requires very low latency and strong consistency across multiple regions, PlanetScale might not be a solid choice.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MySQL compatible (easy for MySQL users)&lt;/td&gt;
&lt;td&gt;Not a distributed database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scales horizontally using Vitess sharding&lt;/td&gt;
&lt;td&gt;Doesn’t shard automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branching mechanism&lt;/td&gt;
&lt;td&gt;No foreign key constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relational data modeling&lt;/td&gt;
&lt;td&gt;No realtime API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;No GraphQL support out of box&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  MongoDB (MongoDB Atlas)
&lt;/h2&gt;

&lt;p&gt;Another popular choice is MongoDB. MongoDB is a NoSQL database with optional schemas. MongoDB is flexible and suitable for both structured and unstructured data. Mongo Atlas provides managed instances of the Mongo database. Mongo saves data in JSON format.&lt;/p&gt;

&lt;p&gt;Assessing the performance of two different database systems is very difficult since both systems approach the task of data storage and retrieval in entirely different ways. MongoDB is also optimized for write performance. Due to its document-oriented nature and prioritizing speed over transaction safety, MongoDB usually outperforms traditional &lt;a href="https://www.thinkautomation.com/eli5/eli5-the-relational-vs-non-relational-database/" rel="noopener noreferrer"&gt;relational databases&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Unlike a relational database, MongoDB doesn’t support foreign key joins. Because of this modeling your data relationships can be tricky with Mongo. There are other ways to get around this problem in MongoDB. Review &lt;a href="https://stackoverflow.com/questions/31480088/join-two-collection-in-mongodb-using-node-js" rel="noopener noreferrer"&gt;this thread&lt;/a&gt; to learn more about data modeling in MongoDB.  &lt;/p&gt;

&lt;p&gt;You create indexes in MongoDB to execute queries and access data efficiently. Without indexes, you must perform a collection scan in MongoDB. If your indexing is incorrectly implemented or has any discrepancies or other errors, it negatively impacts the speed and performance of MongoDB. &lt;/p&gt;

&lt;p&gt;MongoDB Atlas supports GraphQL. You can also use change streams to implement real time functionality. &lt;/p&gt;

&lt;p&gt;One limitation MongoDB is that it is not transactional. If your application requires transactional data MongoDB might not be the right fit. Incorrect or complex indexing coupled with lack of structured relationship can lead to data corruption in MongoDB if not careful.&lt;/p&gt;

&lt;h3&gt;
  
  
  MongoDB Atlas with edge architecture
&lt;/h3&gt;

&lt;p&gt;MongoDB Atlas offers serverless instances of MongoDB; however this is not distributed. Meanwhile, the managed service (provisioned) Atlas offering support global replication of your data out of the box. &lt;/p&gt;

&lt;p&gt;If you want to use your edge architecture to its full potential, you have to replicate data manually and have your database servers located close to your edge servers. Again this can be challenging. &lt;/p&gt;

&lt;p&gt;he provisioned version of MongoDB Atlas also requires TCP/IP to connect with edge functions, which is incongruent with edge/serverless functions that are ephemeral in nature (as you’ll have to maintain connection pools with MongoDB even when the function isn’t being called.&lt;/p&gt;

&lt;p&gt;If your application doesn't require a transactional database, out-of-box multi-region replication mechanism, and you don’t require complex RDBMS like data modeling, then go with MongoDB.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flexible, easy to use query expression&lt;/td&gt;
&lt;td&gt;Need to manage connection pooling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reliable and easy to scale&lt;/td&gt;
&lt;td&gt;Performance costs with distributed transactions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL support through MongoDB Atlas&lt;/td&gt;
&lt;td&gt;Mongo has a hard limit of 16MB per document&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;More performant than any relational database&lt;/td&gt;
&lt;td&gt;Atlas is (or can be) globally distributed, but you need to manage clusters and shard keys&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Fauna
&lt;/h2&gt;

&lt;p&gt;Fauna is a distributed &lt;a href="https://docs.fauna.com/fauna/current/learn/introduction/document_relational" rel="noopener noreferrer"&gt;document-relational database&lt;/a&gt; delivered as a cloud API. Fauna combines the best of both SQL and NoSQL. With Fauna, you get the flexibility of a NoSQL database and a SQL database's relational data modeling capabilities. &lt;/p&gt;

&lt;p&gt;Fauna also has user-defined functions (UDFs) features which allow you to compute on your data and reduce the round trip to your database. Learn more about Fauna’s UDFs &lt;a href="https://docs.fauna.com/fauna/current/api/graphql/functions#:~:text=User%2Ddefined%20functions%20(UDF),placed%20elsewhere%20in%20a%20schema." rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On top of everything Fauna gives you a native &lt;a href="https://docs.fauna.com/fauna/current/learn/quick_start/gql_quick_start" rel="noopener noreferrer"&gt;GraphQL API&lt;/a&gt; to query your database. You get the ability to define your database as a GraphQL schema. You can update and merge the GraphQL schema as your application data evolves without breaking anything. &lt;/p&gt;

&lt;p&gt;You also have the capability to build real-time applications with Fauna's &lt;a href="https://docs.fauna.com/fauna/current/learn/understanding/streaming" rel="noopener noreferrer"&gt;streams API&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;At its core, Fauna uses a proprietary query language called FQL (Fauna Query Language).&lt;/p&gt;

&lt;p&gt;Tip&lt;/p&gt;


&lt;h3&gt;Fauna is natively integrated with Vercel and Netlify&lt;/h3&gt;

&lt;p&gt;
These integrations make it easy to use Fauna as the database for your sites and functions.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.fauna.com/fauna/current/build/integrations/netlify" rel="noopener noreferrer"&gt;Fauna Add-on for Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.fauna.com/fauna/current/build/integrations/vercel" rel="noopener noreferrer"&gt;Vercel integration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3&gt;
  
  
  Fauna and edge architectures
&lt;/h3&gt;

&lt;p&gt;Fauna was built for modern applications. It requires zero configuration and management. Fauna is strongly consistent, serverless, and globally distributed. And because Fauna is globally distributed, your data is automatically replicated and placed closest to your edge servers.&lt;/p&gt;

&lt;p&gt;Fauna is designed to take full advantage of the edge architecture and ensures that your users get the data from the nearest location. Fauna can be accessed through an HTTP call, and unlike MongoDB and some other NoSQL databases, it doesn’t directly rely on underlying TCP/IP for connection.&lt;/p&gt;

&lt;p&gt;If you want the flexibility and performance of NoSQL with the reliability, data modeling, and strong consistency of SQL, then Fauna is the appropriate database for you.&lt;/p&gt;

&lt;p&gt;Fauna's flexible document-relational data modeling (as it combines the best of SQL and NoSQL) makes it a smooth developer experience. Developers also have the option to choose either a driver or GraphQL API to query their database, which in turn makes developers more productive. &lt;/p&gt;

&lt;p&gt;When you build on platforms like Netlify or Vercel, you focus on your code and delivering features fast without thinking about the servers, latency, or scaling up; these platforms take care of everything. Fauna follows the same philosophy. You spin up your database, connect your application, and everything else (i.e., scaling up, global distribution of data, region groups, replication) is taken care of by Fauna.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Document-relational database (Combines the flexibility and performance of NoSQL with the reliability of SQL)&lt;/td&gt;
&lt;td&gt;Fauna Query Language is new and requires some time to get used to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serverless and distributed&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto scales (Pay per usage)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allows compute on data with UDFs&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong consistency&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL support&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real time API support with streams&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Platforms like Vercel and Netlify enable developers to quickly build applications and solutions while simultaneously improving the developer experience. These platforms abstract away server management, scaling, and infrastructure so you and your engineering team can focus on shipping features and writing code. The data layer is critical in developing, launching, and scaling a successful product, so why not choose a database that is also built with the philosophy of serverless edge architecture? You can signup for a free instance (no credit card required) of Fauna &lt;a href="https://dashboard.fauna.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and start building today. I hope this article helps you make an informed decision on your choice of a database while building with Vercel or Netlify.&lt;/p&gt;

</description>
      <category>database</category>
      <category>jamstack</category>
      <category>serverless</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Edge computing reference architectures</title>
      <dc:creator>Fauna</dc:creator>
      <pubDate>Thu, 04 Aug 2022 15:27:10 +0000</pubDate>
      <link>https://forem.com/fauna/edge-computing-reference-architectures-390n</link>
      <guid>https://forem.com/fauna/edge-computing-reference-architectures-390n</guid>
      <description>&lt;p&gt;Cloud computing has transformed how businesses conduct their work, but many face challenges regarding data protection (&lt;a href="https://permission.io/blog/data-residency/"&gt;residency&lt;/a&gt; and &lt;a href="https://permission.io/blog/data-sovereignty/"&gt;sovereignty&lt;/a&gt;), network latency and throughput, and industrial integration. On-premises infrastructure, especially when it’s tightly integrated with edge computing services provided by various cloud platforms such as &lt;a href="https://aws.amazon.com/lambda/edge/"&gt;AWS Lambda@Edge&lt;/a&gt;, &lt;a href="https://workers.cloudflare.com/"&gt;Cloudflare Workers&lt;/a&gt;, &lt;a href="https://www.fastly.com/products/edge-compute"&gt;Fastly Compute@Edge&lt;/a&gt;, etc., can be helpful in solving these problems. But that’s just part of the edge computing puzzle.&lt;/p&gt;

&lt;p&gt;Cloud data centers and on-premises infrastructures form the near edge of the network. The other part of the network can be considered the far edge. Many businesses need the &lt;a href="https://www.forbes.com/sites/forbestechcouncil/2019/11/07/bridging-the-last-mile-convergence-at-the-infrastructure-edge/"&gt;last mile coverage&lt;/a&gt; of the cloud to ensure that the cloud connects and integrates directly with controllers, sensors, and far-end devices. Currently, this workload is handled by specialized programmable logic controllers (PLCs) and human-machine interfaces (HMIs). These devices work great but depend on proprietary operating systems and are costly to acquire, maintain, and upgrade.&lt;/p&gt;

&lt;p&gt;The following table lists the different parts of an edge network and their usual distance from the devices on the far edge of the network, along with the network latency from applications to those devices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;The cloud (regional and zonal data centers)&lt;/strong&gt; — is 10+ km away from edge devices and has a latency of over 10 ms&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Near edge (on-prem data centers)&lt;/strong&gt; — is between 1 to 10 km away from the edge devices and has a latency from 1 to 10 ms&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Far edge L1 (gateways, controllers) &lt;/strong&gt;— is between 10 m to 1 km with a latency of somewhere between 0.1 ms and 1 ms&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Far edge L2 (sensors, devices)&lt;/strong&gt; — is in the 10 m range of the edge devices and has sub-millisecond latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article will take you through some of the edge computing reference architectures proposed by different organizations, researchers, and technologists so that you have a better understanding of the solutions that edge computing offers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do you need edge computing?
&lt;/h2&gt;

&lt;p&gt;Content delivery networks are based on the idea that to provide a great user experience, you need to deliver the content as quickly as possible. You can only do that by physically bridging the network latency gap to place the content closer to your end users. &lt;a href="https://fauna.com/features"&gt;Fast-access storage&lt;/a&gt; solves this problem. Big companies in specific domains like content delivery and mobile networking already use the edge network for storage, if not for computing.&lt;/p&gt;

&lt;p&gt;But many businesses can’t solve their problems with delivery networks; they need computing power without the latency lag of the cloud. They would rather have something closer to the edge in addition to the cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge computing use cases
&lt;/h3&gt;

&lt;p&gt;Take vehicle autonomy, for instance. An average car without autonomy has over fifty sensors that help the vehicle’s critical and non-critical functions. Traditionally these sensors were lightweight, but with autonomous car cameras, LiDAR sensors, and others, there’s an &lt;a href="https://www.forbes.com/sites/forbestechcouncil/2021/09/27/edge-computings-applications-in-autonomous-driving-and-business-at-large/?sh=102143796aa8"&gt;ever-increasing demand for computing power on board&lt;/a&gt;. You can’t rely on APIs and the network for processing specific information in the operations of a critical machine like a car.&lt;br&gt;
Another example is &lt;a href="https://premioinc.com/blogs/blog/rugged-nvr-computers-podcast"&gt;surveillance&lt;/a&gt;. Businesses might use AI and ML applications to process a camera feed in real time. Offloading that amount of raw data to the cloud for processing might not be the wisest decision, as it will need tremendous network bandwidth and computing power to move data back and forth. To save time spent moving data around, you need more computing power at the source, and you can send the workloads that can wait to the cloud.&lt;br&gt;
The same principles apply to many specialized industries, such as aerospace, live entertainment, mass transportation, and manufacturing. This is why the edge is becoming more relevant by the day. Other applications of edge computing include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decoupling automation workloads from specialized hardware like PLCs and HMIs by using open source software like &lt;a href="https://www.freertos.org/openrtos.html"&gt;FreeRTOS&lt;/a&gt; or &lt;a href="https://www.highintegritysystems.com/openrtos/"&gt;OPENRTOS&lt;/a&gt; and running the workloads on containers&lt;/li&gt;
&lt;li&gt;Offloading custom data-intensive critical workloads to the near edge network&lt;/li&gt;
&lt;li&gt;Minimizing your maintenance and downtime with a redundant computing system for your business’s critical systems, which adds real value to your &lt;a href="https://www.ovhcloud.com/en-au/stories/backup-strategy/"&gt;business continuity planning (BCP) and disaster recovery planning (DRP) efforts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Optimizing business processing with the help of faster response times from the computing power on the network’s edge&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;Interested in understanding edge computing beyond its use in IoT?&lt;/h3&gt;

&lt;p&gt;
Fauna can help you build faster, more performant edge applications. Since Fauna is distributed dy default, you can reduce latency for your apps with a close-proximity database for your edge nodes. Easily integrate with Cloudlfare workers and Fastly Compute@Edge platforms out of the box.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://go.fauna.com/campaign-fauna-edge"&gt;On-demand webinar: Realize the full potential of your edge architecture with Fauna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.fauna.com/fauna/current/build/integrations/cloudflare"&gt;Getting started with Fauna and Cloudflare Workers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.fauna.com/fauna/current/build/integrations/fastly"&gt;How to build an edge API gateway with Fastly's Compute@Edge and Fauna&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Edge computing reference architectures
&lt;/h2&gt;

&lt;p&gt;To properly design and implement edge computing networks, businesses rely on reference architectures. The following are some reasons why they’re an invaluable resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design considerations
&lt;/h3&gt;

&lt;p&gt;Businesses are still finding different ways to exploit the power of edge computing, and edge computing reference architectures help them understand systems that could potentially work for them. Not only are these reference architecture patterns well researched and thought out by industry experts, but they try to encapsulate the key features that apply to various businesses.&lt;/p&gt;

&lt;p&gt;You can use reference architectures for inspiration as well as innovate on top of them. There are several factors and design considerations that you should take into account while architecting an edge computing system for your business:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time sensitivity:&lt;/strong&gt; With edge computing, critical business functions don’t have to wait for workloads to be offloaded to the cloud for processing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network bandwidth:&lt;/strong&gt; Bandwidth is limited; you don’t want to choke the network by blocking other important operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security and privacy:&lt;/strong&gt; Data sovereignty and data residency, both for security and privacy, can be enabled by the edge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational continuity:&lt;/strong&gt; During network disruptions, you can offload the extremely critical operations of your business to the edge&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementation outcomes
&lt;/h3&gt;

&lt;p&gt;The outcomes and benefits of architecting edge computing systems align strongly with the abovementioned factors. With a successfully deployed edge computing system, your business gains the following core benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Significantly lower latency and higher network bandwidth by utilizing the proximity from the request origin to the computing system&lt;/li&gt;
&lt;li&gt;Effective network use by filtering and reducing farther data transfer to on-premises or cloud infrastructure&lt;/li&gt;
&lt;li&gt;Better enforcement of security and privacy standards, enabling data sovereignty and data residency&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Development and deployment plans
&lt;/h3&gt;

&lt;p&gt;When developing for the edge, businesses need to ensure that they don’t end up creating the same dependencies and bottlenecks they experienced when using only on-premises data centers or the cloud.&lt;/p&gt;

&lt;p&gt;An excellent way to do this is to research, identify, and pick the right open standards and technologies to help you get the architecture you want. Possible open standards include those for APIs, documentation, virtualization patterns, deployment pipelines, and code promotion strategies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge computing reference architectures that use Fauna
&lt;/h2&gt;

&lt;p&gt;There are many reference architectures, some of which heavily borrow from one another. However, each has a unique approach and feature set. &lt;a href="https://fauna.com/"&gt;Fauna&lt;/a&gt;, as a distributed general-purpose database, interacts well with all of them in different ways.&lt;/p&gt;

&lt;p&gt;The following are details on four reference architectures, their relevance and innovation, and how to adopt them with Fauna.&lt;/p&gt;

&lt;h3&gt;
  
  
  Industrial internet reference architecture
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.iiconsortium.org/pdf/IIRA-v1.9.pdf"&gt;Industrial Internet Reference Architecture&lt;/a&gt; (IIRA) was first developed in 2015 by the &lt;a href="https://www.iiconsortium.org/"&gt;Industry IoT Consortium&lt;/a&gt; (IIC). This was a collaborative effort from a range of companies, including Bosch and Boeing in manufacturing; Samsung and Huawei in consumer electronics; and IBM, Intel, Microsoft, SAP, Oracle, and Cisco in the software industry.&lt;/p&gt;

&lt;p&gt;Think of IIRA as having four different viewpoints: business, functional, usage, and implementation. The system is divided into enterprise, platform, and edge. You have low-level devices in factories or appliances at the edge, connected with the platform tier using low-level APIs. Data collected from these devices flows to data and analytics services and operations users.&lt;/p&gt;

&lt;p&gt;The data generated by the edge, along with the data and insights gathered and processed by the platform tier, is consumed by the enterprise tier on two levels: the business domain and app domain. The data in the business domain lands in other systems, such as ERP, and the data in the app domain flows further based on business logic and rules to the business users in the form of mobile apps, browser-based frontend applications, or business intelligence tools.&lt;/p&gt;

&lt;p&gt;The following diagram shows the three-tiered approach to IIoT system architecture using IIRA:&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/3X6nUX1YmYwmlnFVY93qr5/9f87a79ce9b1b3d2fb4640c92d213af6/Three-tier_IIOT_System_Architecture.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/3X6nUX1YmYwmlnFVY93qr5/9f87a79ce9b1b3d2fb4640c92d213af6/Three-tier_IIOT_System_Architecture.png" alt="Three-tier IIoT system architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fauna’s &lt;a href="https://fauna.com/platform#distributed-compute-storage"&gt;distributed architecture&lt;/a&gt; allows it to sit across multiple layers of the network while simultaneously guaranteeing you the privileges of a &lt;a href="https://fauna.com/platform#compute-engine"&gt;flexible document-oriented database and ACID transactions&lt;/a&gt;. The data and analytics services and platforms can heavily interact with Fauna, and the operations services and platform will do the same. In this context, Fauna sits mainly on the platform tier but interacts with the edge tier, depending on whether the devices are integrated with the platform tier using a virtualization layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  FAR-EDGE reference architecture
&lt;/h3&gt;

&lt;p&gt;Aside from the previously mentioned features of reference architectures, the &lt;a href="https://www.riverpublishers.com/pdf/ebook/chapter/RP_9788770220408C3.pdf"&gt;FAR-EDGE Reference Architecture&lt;/a&gt; brings &lt;a href="https://wiki.openstack.org/wiki/Edge_Computing_Group/Edge_Reference_Architectures"&gt;many new things&lt;/a&gt; to the table. It explicitly offers a separate logical and ledger layer that handles processes and rules across the distributed computing system by using the sheer power and spread of the system. Like most edge computing reference architectures, FAR-EDGE also concentrates on saving bandwidth and storage, enabling ultra-low latency, proximity processing, and enhanced scalability by exploiting the distributed nature of the edge-cloud hybrid architecture.&lt;/p&gt;

&lt;p&gt;Compare the idea of FAR-EDGE with some of the Web3 architectures built on top of distributed frameworks like the blockchain. Fauna, with its &lt;a href="https://fauna.com/blog/how-to-build-an-edge-api-gateway-with-fastlys-compute-edge-and-fauna"&gt;capability to provide edge functions&lt;/a&gt; as an extension to the application infrastructure, can play a central role by servicing various layers and functions proposed in this reference architecture. Consider the functional view of the FAR-EDGE reference architecture below:&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/6ey7VZmZOWSMiaQeUzW2ZI/573d66d8a86c24952bf01a44ecf637cc/umnZfIY.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/6ey7VZmZOWSMiaQeUzW2ZI/573d66d8a86c24952bf01a44ecf637cc/umnZfIY.png" alt="A functional view of the FAR-EDGE reference architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s worth reiterating that Fauna is a distributed document-relational database, which is ideal for businesses with a variety of software applications and hardware devices. In this functional view, Fauna will sit and interact not only with applications and cloud services but also with ledger and edge processes at the ledger and gateway levels. You can enable this by using well-documented APIs and SDKs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge computing reference architecture 2.0
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="http://en.ecconsortium.org/"&gt;Edge Computing Consortium&lt;/a&gt; (ECC) proposed a model-driven reference architecture that attempts to solve the problems businesses face when they try to connect the digital and the physical worlds. Since the reference architecture is multidimensional, you can regard it from different viewpoints. Consider one of its layers, the Edge Computing Node layer, from a functional viewpoint.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://en.ecconsortium.net/Uploads/file/20180328/1522232376480704.pdf"&gt;Edge Computing Reference Architecture 2.0&lt;/a&gt; is a multidimensional architecture composed of the following components from a high-level view: smart services, a service fabric, a &lt;a href="https://www.ericsson.com/en/reports-and-papers/ericsson-technology-review/articles/network-compute-fabric"&gt;Connectivity and Computing Fabric&lt;/a&gt; (CCF), and Edge Computing Nodes (ECNs).&lt;/p&gt;

&lt;p&gt;As mentioned earlier, edge computing thrives when open standards are followed and hardware devices are decoupled from specifically designed hardware. This problem has long been solved for specific web and desktop applications via virtualization. The Edge Computing Reference Architecture also suggests you create an &lt;a href="https://blog.stratus.com/5-benefits-virtualization-at-the-edge/"&gt;Edge Virtualization Function (EVF) layer&lt;/a&gt; that handles connectivity and &lt;a href="https://fauna.com/features#event-streaming"&gt;data streaming and collection&lt;/a&gt;, along with access policies and security.&lt;/p&gt;

&lt;p&gt;The following diagram of the Edge Computing Reference Architecture 2.0 shows the functional view of an Edge Computing Node (ECN):&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/po4qc9xpmpuh/2Kc43cmfWF5C2hh6Uejkdt/9a3b56d31f2778b708f4e463730e808f/Edge_computing_node.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/po4qc9xpmpuh/2Kc43cmfWF5C2hh6Uejkdt/9a3b56d31f2778b708f4e463730e808f/Edge_computing_node.png" alt="Edge computing node"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fauna is more than capable of taking care of the universal services, such as streaming and time series data, along with any industry-oriented services that might need integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Edge computing reference architectures can vastly simplify the design and usage of edge computing systems, and &lt;a href="https://fauna.com/"&gt;Fauna&lt;/a&gt; can help at different levels in all these architectures. Fauna is a natively serverless, &lt;a href="https://fauna.com/features#document-relational"&gt;distributed transactional&lt;/a&gt; database that allows for flexible schemas and comes with a well-designed data API for modern applications.&lt;/p&gt;

&lt;p&gt;With Fauna in the cloud and at the edge, you can store and retrieve your data at ultra-low latencies while being closer to the source than ever before. With built-in &lt;a href="https://fauna.com/features#modern-security-model"&gt;data security, authentication, authorization, and attribute-based access control&lt;/a&gt;, Fauna simplifies the implementation of edge computing reference architectures and lets you concentrate more on your business.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>iot</category>
    </item>
    <item>
      <title>Modernization of the database: DynamoDB to Fauna</title>
      <dc:creator>Fauna</dc:creator>
      <pubDate>Mon, 25 Jul 2022 14:16:10 +0000</pubDate>
      <link>https://forem.com/fauna/modernization-of-the-database-dynamodb-to-fauna-5bc1</link>
      <guid>https://forem.com/fauna/modernization-of-the-database-dynamodb-to-fauna-5bc1</guid>
      <description>&lt;p&gt;Serverless databases like &lt;a href="https://fauna.com/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;Fauna&lt;/a&gt; fill a crucial role for modern applications. Given the amount of cloud-based traffic and varying workloads that organizations from startups to enterprises manage, serverless databases are the natural fit to the rest of your serverless architecture, adding seamless flexibility, scaling, and low latency for your applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/dynamodb/"&gt;DynamoDB&lt;/a&gt; has been one of the most popular serverless databases. In addition to coming from AWS, it has benefited from being one of the earliest offerings in this space. Its popularity is hard to dispute, backed up by its proven ability to effectively handle traffic spikes and workload variations without overloading infrastructure or racking up unnecessary costs during periods of low traffic. Though DynamoDB has much to offer, Fauna is a much newer offering that comes with a host of powerful and unique features that enhance the serverless experience for organizations of all sizes.&lt;/p&gt;

&lt;p&gt;In this article, we’ll learn about serverless databases, compare key differences between DynamoDB and Fauna, and provide insight on which one to choose for your next big project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a good serverless database?
&lt;/h2&gt;

&lt;p&gt;A great serverless database should offer the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lower operation costs:&lt;/strong&gt; One of the main reasons for choosing software is cost. Traditionally, organizations need to budget for the continuous management of their database(s) and infrastructure, and not just for application development. Serverless architectures promise “zero ops,” which eliminate these management concerns. As headcount makes up your highest spend, leaning out on operations overhead ultimately lowers your TCO (total cost of ownership).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pay as you go:&lt;/strong&gt; It should also offer a simple and transparent pricing model without any traps or unexpected costs. You should only have to pay for the resources you use, with billing being proportional to the amount of data stored and volume of transactions sent to the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High availability:&lt;/strong&gt; There should be no maintenance windows or unplanned downtimes. Data and compute resources should be automatically distributed and replicated, offering high durability and resiliency to region/zone outages. The more these attributes are provided to the operator without any additional configuration, the better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low latency:&lt;/strong&gt; Ensuring a good user experience is key to user engagement, ultimately impacting how successful your products are with customers. Serverless architectures should not trade off the ability to scale elastically with cold start-up delays or increased latency due to speed-of-light constraints. A great serverless database offering should be always-on and instantly scale; And provide multiple region choices so that it can be accessed as close to your compute resources as possible. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why should you choose Fauna?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://fauna.com/blog/intro-to-serverless-databases?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;Serverless databases&lt;/a&gt; are critical components for managing unpredictable and rapidly changing workloads, essentially following a pay-as-you-use model. They are also a good fit for companies with a small workforce, enabling them to consume compute workloads and infrastructure without manual overhead. Using a serverless database allows you to simplify database operations and eliminate problems common with traditional databases, such as maintenance, upgrades and patching, and cost of operations.&lt;/p&gt;

&lt;p&gt;Fauna is accessed as an API and there is nothing to install, maintain, or operate. You can quickly deploy a database in three button clicks, start coding, and immediately connect to the database. You can scale databases without any limitations and create an unlimited number of databases. It is chock full of cloud-native features: login with your GitHub account; integrate with third-party services like Auth0, Netlify, and Vercel; has built-in streaming, user authentication and fine-grain authorization. It supports user-defined functions – similar to stored procedures – which help eliminate redundant code, maintain Fauna Query Language (FQL) consistency, and remove code duplication. And it has a native GraphQL API, allowing organizations adopting GraphQL to quickly get up and running with a data source in minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fauna vs. DynamoDB
&lt;/h2&gt;

&lt;p&gt;Fauna offers numerous features that distinguish it from DynamoDB and similar serverless databases. The following is a comparison between Fauna and DynamoDB and the components that each offers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Geo-distribution
&lt;/h3&gt;

&lt;p&gt;Businesses with global audiences need to ensure fast response and high performance for customers in multiple regions across the globe. This requires a database that allows data to be replicated globally and served from specified locations — the closer the proximity of the data, the better the experience and performance.&lt;/p&gt;

&lt;p&gt;By default, DynamoDB is replicated across multiple availability zones in a single region. But with the “global tables” feature, DynamoDB provides a fully managed solution for deploying a multi-region, multi-active database. You specify the regions you want the database to replicate, and DynamoDB will propagate all data changes to them. Besides reducing read latency, multi-region replication ensures that single region failures do not result in any outages. Using global tables comes with quite a few caveats. Your application can read and write to any replica table, but if it requires strongly consistent reads, it must perform all its strongly consistent reads and writes against the same region. AWS documentation states that any newly written item is propagated to all replica tables within a second — not an insignificant latency — and that ACID guarantees only apply within the AWS Region where the write was originally made. When an AWS region suffers an outage or degradation, your application can redirect to a healthy region but it isn’t automatic: AWS documentation prompts developers to apply custom business logic to determine when to redirect requests to other regions. Global tables are more costly to operate. Your costs essentially multiply several times with the addition of every replica. In addition, you must also use the higher priced on-demand capacity mode, though this can be mitigated as they allow the use of provisioned capacity with auto-scaling.&lt;/p&gt;

&lt;p&gt;Unlike DynamoDB, Fauna is multi-region-distributed by default — every database you create is replicated and distributed across geographic regions. In addition, Fauna also provides the &lt;a href="https://docs.fauna.com/fauna/current/learn/understanding/region_groups?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;Region Groups&lt;/a&gt; functionality, which allows developers to control which region their data resides in. Other than selecting the Region Group, there is no additional configuration and no custom business logic to implement. When your application makes a request to the Fauna API, it is automatically routed to the region closest to it. Reads are immediately served out of that region. And writes are automatically propagated to the other regions’ replicas automatically. Fauna publicly publishes its &lt;a href="https://fauna.com/blog/real-world-database-latency?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;“internal latency”&lt;/a&gt; – separated into reads and writes – on &lt;a href="https://status.fauna.com/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;status.fauna.com&lt;/a&gt;. There is no separate pricing scheme for single- vs multi-region with Fauna since your databases are always multi-region – providing you straightforward and transparent pricing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transactionality
&lt;/h3&gt;

&lt;p&gt;While you want to ensure the real-time availability of data, your data needs to be consistent and accurate. Not all serverless databases can provide this.&lt;/p&gt;

&lt;p&gt;DynamoDB, for instance, offers serializable read and write transactions but is only ACID-compliant within the region where the transaction occurs. This is a problem for multi-region deployments, because it can lead to errors during transactions that run simultaneously in different regions.&lt;/p&gt;

&lt;p&gt;One of Fauna’s most touted innovations is its approach to isolation and distribution, which is derived from &lt;a href="https://fauna.com/blog/consistency-without-clocks-faunadb-transaction-protocol?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;Calvin&lt;/a&gt;, an algorithm for achieving distributed consistency at scale. As an oversimplified explanation to what it entails, queries are handled before they interact with the storage system, while deterministic ordering – eschewing the need for expensive atomic-clocks – is employed to provide serializability, ensuring that no two concurrent transactions can commit to the same data. Through Fauna’s Calvin implementation, it is one of the few serverless databases that offers &lt;a href="https://fauna.com/blog/faunadbs-official-jepsen-results?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;ACID&lt;/a&gt; guarantees while being globally distributed at the same time. Transactions are globally distributed, ACID-compliant, and serializable, with no additional configuration or separate pricing scheme.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streaming
&lt;/h3&gt;

&lt;p&gt;Real-time applications require an endpoint that enables persistent connectivity, allowing the server to push information to the client requesting it. &lt;/p&gt;

&lt;p&gt;With DynamoDB, you’ll need to combine several services in order to implement streaming. The first part is setting up a DynamoDB Stream: DynamoDB integrates with AWS Lambda, where you set up triggers that respond to changes (DynamoDB Stream events) in your table(s). Thus, there’s a bit of configuration, and some coding involved in writing the Lambda. From there, you need to implement the persistent endpoint. AWS can accomplish this in a number of ways, and your choices are using either an EC2, API Gateway Websocket API, or AppSync (via GraphQL Streaming). Regardless, these are additional components that need to be implemented and/or configured and maintained. On top of that are the costs involved in running the additional services.  &lt;/p&gt;

&lt;p&gt;In contrast, Fauna’s API endpoints support streaming right out of the box. In order to consume a stream, all you need to do is write some lines of code on the client side of your application using a driver in your language of choice. For example, here are the instructions for instantiating a stream client in &lt;a href="https://docs.fauna.com/fauna/current/drivers/javascript?lang=shell#streaming?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;javascript&lt;/a&gt;. Fauna offers two kinds of streaming: document streaming and set streaming. With document streaming, an event notification is sent to the subscriber whenever a document is created, updated, or deleted. With set streaming, events are sent whenever one or more documents enter or exit the set while doing a create, delete, or update.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;Because they are accessed as APIs, great serverless databases must provide robust security models, so that developers do not have to build their own authentication and authorization. &lt;/p&gt;

&lt;p&gt;Access to DynamoDB is based on AWS’s highly robust Identity and Access Management (IAM), in which granular permissions are applicable to the DynamoDB resources (tables, indexes, and stream). You can also specify IAM policies that grant access to perform specific actions (e.g, read, add, update, batch update, etc.) on specific resources for specific users.&lt;/p&gt;

&lt;p&gt;Fauna supports both API keys and identity-based access tokens, and supports integration with external identity providers that support the OAuth flow (such as Auth0, Okta, OneLogin, etc.). Keys and tokens inherit the permissions of roles upon which they’re assigned. Roles are configured with granular permissions to access every single resource in the database, including collections (tables), indexes, user-defined functions, other roles, and schema. Fauna also provides attribute-based access control (ABAC), allowing permissions to be dynamically assigned based on tokens’ identities’ attributes. With ABAC, you can define custom business logic, creating dynamic rules that control access to all resources, all the way down to specific documents in a collection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automated functionalities
&lt;/h3&gt;

&lt;p&gt;In DynamoDB, a host of configuration options allow you to operate various capacity modes, single- vs. multi-region, types of indexes and index-partitioning strategy used, logging, and more. The tradeoff for this flexibility is more manual work and time.&lt;/p&gt;

&lt;p&gt;Fauna, however, automates multiple functions for you, such as database provisioning, maintenance, sharding, scaling, and replication. The “zero ops” model of Fauna lets you focus on building the critical aspects of your applications without worrying about the complexity of a distributed architecture. This is especially useful if your business needs to carefully manage limited engineering resources while dealing with unpredictable workloads. &lt;/p&gt;

&lt;p&gt;DynamoDB includes an automated backup feature. It charges for backups separately, and you need to select from on-demand or continuous backups. The backup is optional and by project. &lt;/p&gt;

&lt;p&gt;In Fauna, you can schedule daily backups on any database in the form of snapshots of the entire data-tree. You can also configure a retention period for them. Databases can be “restored” (overridden) in place from any backup, or you can use backups to seed new databases. Fauna also supports temporality, allowing you to go back through history and query data at any arbitrary point in time. This is because in Fauna, data is stored as snapshots across time. You can use this feature to implement point-in-time recovery and targeted data repairs in your database.&lt;/p&gt;

&lt;h3&gt;
  
  
  GraphQL API support
&lt;/h3&gt;

&lt;p&gt;GraphQL is designed to make API development faster and more flexible for software engineers. API developers use GraphQL to have a schema that will showcase all the possible data that the clients will want to query through a specific endpoint. Unlike most other serverless databases like DynamoDB and Upstash, Fauna provides a native GraphQL API for data access in addition to its query language, FQL.&lt;/p&gt;

&lt;p&gt;If you are looking to launch your product in less time and expect a lot of changes on your API endpoint, then using a serverless database that supports GraphQL APIs will be the better choice for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Check out our GraphQL workshop that introduces you to Fauna. In two hours, you’ll build an application in either Next.js or SvelteKit that has authentication, user-defined functions, customer resolvers, and more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Scalability and pricing
&lt;/h3&gt;

&lt;p&gt;With some serverless databases like DynamoDB, automatic scaling is an option but isn’t set by default. There are basically three modes in DynamoDB:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The default – called provisioned capacity –&lt;/strong&gt; lets you set the volume and scale that you need up front. You then either manually monitor and manage these parameters or be automatically throttled once the load hits your predefined capacities. This mode is ideal when you have steady, predictable loads, and you need to stay within a narrow budget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provisioned capacity with auto-scaling&lt;/strong&gt; is the same as provisioned capacity but also dynamically adjusts throughput capacity based on actual traffic, allowing your application to handle sudden bursts in traffic without being throttled. Pricing is a factor of the baseline capacity you’ve configured and your application's actual load (above that baseline) that your application experiences. It is important to note that because provisioned capacity (with or without auto-scaling) involves setting a baseline desired capacity, you are always paying for that capacity, even when your traffic is zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-demand capacity&lt;/strong&gt; is priced significantly higher (on a per-unit read/write/etc. basis) than provisioned capacity, but is truly serverless and will scale to zero (where you pay nothing) if no traffic is observed or as high as needed when bursts are experienced.&lt;/p&gt;

&lt;p&gt;The one and only mode in Fauna is on-demand. It autoscales without any intervention from you and you don’t need to manage the settings of the desired throughput. There is no need to monitor the database to keep your database safe from being saturated. As such, pricing is much more straightforward and only a factor of how much data you store, how many transactions occurred, and how large (complex) the transactions/queries are. Comparison pricing between Fauna and DynamoDB is highly based on context and use-case and especially how you plan to use DynamoDB, given its flexibility in setting things up. We cover these topics in &lt;a href="https://fauna.com/blog/comparing-fauna-and-dynamodb-pricing-features?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;“Comparing Fauna and DynamoDB: Pricing and features.”&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Serverless databases offer numerous benefits, including lower costs, less operational workload, faster time to market, and high scalability. When choosing a serverless database, be sure to select one that offers you maximum consistency, high performance, and low latency.&lt;/p&gt;

&lt;p&gt;While there are many serverless databases to choose from, &lt;a href="https://fauna.com/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;Fauna&lt;/a&gt; offers the largest range of features for your organization’s needs. Automated scaling, multi-region ACID-compliant transactions, and GraphQL support will help you optimize your workload and improve your product for users. Your developers can focus on improving your applications and core services while worrying less about managing the database or infrastructure. This leads to a shorter development time and faster application delivery.&lt;/p&gt;

&lt;p&gt;Interested in learning more about Fauna? &lt;a href="https://go.fauna.com/contact-us?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;Reach out to our team&lt;/a&gt; or &lt;a href="https://dashboard.fauna.com/accounts/register?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=fauna-vs-dynamo"&gt;sign up&lt;/a&gt; and start using Fauna for free.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>fauna</category>
      <category>aws</category>
      <category>database</category>
    </item>
  </channel>
</rss>
