01 Tutorials

Languages:

Introduction

FaunaDB allows you to store objects and query them in a relational fashion. In this tutorial, we will learn how to create blog posts, update them with additional attributes and query for specific posts.

Getting Started

To follow along you will need an admin API key. Create an admin key using the admin keys interface for your FaunaDB Cloud account, or if you are using FaunaDB Enterprise, use the configured root key for your cluster.

Create a Database


curl https://db.fauna.com/ \
    -u kqnPAi3Kj3ZgAAC0Hu51Ng2dtn0JcgP7Fb-Q_uzLGZE: \
    -d '{ "create_database": { "object": { "name": "my_app" } } }'

FaunaClient adminClient = FaunaClient.builder()
  .withSecret(adminKey)
  .build();

adminClient.query(CreateDatabase(Obj("name", Value("my_app"))));

var adminClient = new faunadb.Client({
  secret: adminKey
});

adminClient.query(q.CreateDatabase({ name: "my_app" }));

val adminClient = FaunaClient(secret = adminKey)

adminClient.query(CreateDatabase(Obj("name" -> "my_app")))

$admin_client = Fauna::Client.new(secret: adminKey)

$admin_client.query do
  create_database name: 'my_app'
end

var adminClient = new FaunaClient(secret: adminKey);

adminClient.Query(CreateDatabase(Obj("name", "my_app")));

adminClient = FaunaClient(secret=adminKey)

adminClient.query(q.create_database({"name": "my_app"}))

adminClient = f.NewFaunaClient(adminKey)

adminClient.Query(f.CreateDatabase(f.Obj{"name": "my_app"}))

let adminClient = FaunaDB.Client(secret: adminKey)

adminClient.query(CreateDatabase(Obj("name" => "my_app")))

HTTP/1.1 201 Created
{
  "resource": {
    "ref": { "@ref": "databases/my_app" },
    "class": { "@ref": "databases" },
    "ts": 1436375112141542,
    "name": "my_app"
  }
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

=> {
  "ref": { "@ref": "databases/my_app" },
  "class": { "@ref": "databases" },
  "ts": 1436375112141542,
  "name": "my_app"
}

Getting Access to the Database

Create an initial server key for our database by using an admin key. The server key has unrestricted access to a single database.


curl https://db.fauna.com/ \
    -u kqnPAi3Kj3ZgAAC0Hu51Ng2dtn0JcgP7Fb-Q_uzLGZE: \
    -d '{
          "create_key": {
            "object": { "database": { "database": "my_app" }, "role": "server" }
          }
        }'

Value key = adminClient.query(
  CreateKey(
    Obj(
      "database", Database(Value("my_app")),
      "role", Value("server")
    ))).get(1, TimeUnit.SECONDS); // block thread until key gets created

String serverKey = key.get(Field.at("secret").to(Codec.STRING));

var serverKey;
adminClient.query(
  q.CreateKey(
    { database: q.Database("my_app"), role: "server" }))
  .then(function(key) { serverKey = key.secret; });

val keyF = adminClient.query(
  CreateKey(
    Obj("database" -> Database("my_app"), "role" -> "server")))

val key = Await.result(keyF, 1.second) // block thread until key gets created
val serverKey = key(Field("secret").to[String]).get

key = $admin_client.query do
  create_key database: database('my_app'), role: 'server'
end

serverKey = key[:secret]

var key = await adminClient.Query(
  CreateKey(
    Obj("database", Database("my_app"), "role", "server")));

var serverKey = key.Get(Field.At("secret").To(Codec.STRING));

key = adminClient.query(
  q.create_key(
    {"database": q.database("my_app"), "role": "server"}
  ))

serverKey = key["secret"]

var serverKey string

key, _ := adminClient.Query(
    f.CreateKey(
        f.Obj{"database": f.Database("my_app"), "role": "server"},
    ),
)

_ = key.At(f.ObjKey("secret")).Get(&serverKey)

adminClient.query(
    CreateKey(
        Obj(
            "database" => Database("my_app"),
            "role" => "server"
        )
    )
)

HTTP/1.1 201 Created
{
  "resource": {
    "ref": { "@ref": "keys/104979509692858368" },
    "class": { "@ref": "keys" },
    "ts": 1436375112199704,
    "database": { "@ref": "databases/my_app" },
    "role": "server",
    "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
    "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
  }
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

=> {
  "ref": { "@ref": "keys/104979509692858368" },
  "class": { "@ref": "keys" },
  "ts": 1436375112199704,
  "database": { "@ref": "databases/my_app" },
  "role": "server",
  "secret": "kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI",
  "hashed_secret": "$2a$05$.saZ/E/JSuEEkbIfTU/GN.7iKEBBpBGePtWe/mZyL/rmf4uXeZ5oi"
}

Initial Schema

FaunaDB is an object-relational database that stores data in the form of nested objects. Each object is considered an instance of a specific class. Therefore, in order to create an instance of a post, we need to first specify a class such as “posts”.

Create a class using the create_class function with a parameters object containing the name of the class. For example:


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{ "create_class": { "object": { "name": "posts" } } }'

FaunaClient client = FaunaClient.builder()
  .withSecret(serverKey)
  .build();

client.query(CreateClass(Obj("name", Value("posts"))));

var client = new faunadb.Client({
  secret: serverKey
});

client.query(q.CreateClass({ name: "posts" }));

val client = FaunaClient(secret = serverKey)

client.query(CreateClass(Obj("name" -> "posts")))

$client = Fauna::Client.new(secret: serverKey)

$client.query do
  create_class name: 'posts'
end

var client = new FaunaClient(secret: serverKey);

client.Query(CreateClass(Obj("name", "posts")));

client = FaunaClient(secret=serverKey)

client.query(q.create_class({"name": "posts"}))

client = f.NewFaunaClient(serverKey)

client.Query(f.CreateClass(f.Obj{"name": "posts"}))

let client = FaunaDB.Client(secret: serverKey)

client.query(CreateClass(Obj("name" => "posts")))

HTTP/1.1 201 Created
{
  "resource": {
    "ref": { "@ref": "classes/posts" },
    "class": { "@ref": "classes" },
    "ts": 1436375112257866,
    "history_days": 30,
    "name": "posts"
  }
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

=> {
  "ref": { "@ref": "classes/posts" },
  "class": { "@ref": "classes" },
  "ts": 1436375112257866,
  "history_days": 30,
  "name": "posts"
}

Working with Data

Creating a Post

Posts are created by calling the create function with the ref of the “posts” class and a params object. The post’s data is included in the params object’s “data” field.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "create": { "class": "posts" },
          "params": {
            "object": {
              "data": { "object": { "title": "What I had for breakfast .." } }
            }
          }
        }'

client.query(
  Create(
    Class(Value("posts")),
    Obj(
      "data", Obj("title", Value("What I had for breakfast .."))
    )));

client.query(
  q.Create(
    q.Class("posts"),
    { data: { title: "What I had for breakfast .." } }));

client.query(
  Create(
    Class("posts"),
    Obj("data" -> Obj("title" -> "What I had for breakfast .."))))

$client.query do
  create class_('posts'),
         data: { title: 'What I had for breakfast ..' }
end

client.Query(
  Create(
    Class("posts"),
    Obj("data", Obj("title", "What I had for breakfast .."))));

client.query(
  q.create(
    q.class_expr("posts"),
    {"data": {"title": "What I had for breakfast .."}}
  ))

client.Query(
    f.Create(
        f.Class("posts"),
        f.Obj{"data": f.Obj{"title": "What I had for breakfast .."}},
    ),
)

client.query(
    Create(
        at: Class("posts"),
        Obj(
            "data" => Obj("title" => "What I had for breakfast ..")
        )
    )
)

HTTP/1.1 201 Created
{
  "resource": {
    "ref": { "@ref": "classes/posts/104979509693618791" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112432352,
    "data": { "title": "What I had for breakfast .." }
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

=> {
  "ref": { "@ref": "classes/posts/104979509693618791" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112432352,
  "data": { "title": "What I had for breakfast .." }
}

create returns the post instance just created. The ref of the instance is an automatically generated identifier that is unique to the instance within its database.

It can quickly become tedious to repeat the create function for multiple posts.

This is where FaunaDB’s query language really shines. Let’s use a map function to create several posts at once.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "map": {
            "lambda": "post_title",
            "expr": {
              "create": { "class": "posts" },
              "params": {
                "object": {
                  "data": { "object": { "title": { "var": "post_title" } } }
                }
              }
            }
          },
          "collection": [
            "My cat and other marvels",
            "Pondering during a commute",
            "Deep meanings in a latte"
          ]
        }'

client.query(
  Map(
    Arr(
      Value("My cat and other marvels"),
      Value("Pondering during a commute"),
      Value("Deep meanings in a latte")
    ),
    Lambda(
      Value("post_title"),
      Create(
        Class(Value("posts")),
        Obj("data", Obj("title", Var("post_title")))))));

client.query(
  q.Map(
    [
      "My cat and other marvels",
      "Pondering during a commute",
      "Deep meanings in a latte"
    ],
    function(post_title) {
      return q.Create(
        q.Class("posts"),
        { data: { title: post_title } });
    }));

client.query(
  Map(
    Arr(
      "My cat and other marvels",
      "Pondering during a commute",
      "Deep meanings in a latte"
    ),
    Lambda { post_title =>
      Create(
        Class("posts"),
        Obj("data" -> Obj("title" -> post_title)))
    }))

$client.query do
  map [
    'My cat and other marvels',
    'Pondering during a commute',
    'Deep meanings in a latte'
  ] do |post_title|
    create(class_('posts'), data: { title: post_title })
  end
end

client.Query(
  Map(
    Arr(
      "My cat and other marvels",
      "Pondering during a commute",
      "Deep meanings in a latte"
    ),
    post_title => Create(
      Class("posts"),
      Obj("data", Obj("title", post_title)))));

client.query(
  q.map_expr(
    lambda post_title: q.create(
      q.class_expr("posts"),
      {"data": {"title": post_title}}
    ),
    [
      "My cat and other marvels",
      "Pondering during a commute",
      "Deep meanings in a latte"
    ]
  ))

client.Query(
    f.Map(
        f.Arr{
            "My cat and other marvels",
            "Pondering during a commute",
            "Deep meanings in a latte",
        },
        f.Lambda(
            "post_title",
            f.Create(
                f.Class("posts"),
                f.Obj{"data": f.Obj{"title": f.Var("post_title")}},
            ),
        ),
    ),
)

client.query(
    Map(
        collection: Arr(
            "My cat and other marvels",
            "Pondering during a commute",
            "Deep meanings in a latte"
        ),
        to: { postTitle in
            Create(
                at: Class("posts"),
                Obj("data" => Obj("title" => postTitle))
            )
        }
    )
)

HTTP/1.1 200 OK
{
  "resource": [
    {
      "ref": { "@ref": "classes/posts/104979509694379214" },
      "class": { "@ref": "classes/posts" },
      "ts": 1436375112490514,
      "data": { "title": "My cat and other marvels" }
    },
    {
      "ref": { "@ref": "classes/posts/104979509695139637" },
      "class": { "@ref": "classes/posts" },
      "ts": 1436375112490514,
      "data": { "title": "Pondering during a commute" }
    },
    {
      "ref": { "@ref": "classes/posts/104979509695900060" },
      "class": { "@ref": "classes/posts" },
      "ts": 1436375112490514,
      "data": { "title": "Deep meanings in a latte" }
    }
  ]
}

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

=> [
  {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695139637" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Pondering during a commute" }
  },
  {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
]

As you can see above, using the map function, we can restructure the data as a collection and wrap the create in a Lisp-style lambda function, which then runs over each object in the collection. The anonymous lambda function specifies a variable post_title which is used as a placeholder in the parameters sent to the create function. This way, multiple instances of a class can be created using a single query.

Retrieving Posts

The easiest way to retrieve an instance is using its reference value.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{ "get": { "@ref": "classes/posts/104979509694379214" } }'

client.query(Get(Ref("classes/posts/104979509694379214")));

client.query(q.Get(Ref("classes/posts/104979509694379214")));

client.query(Get(Ref("classes/posts/104979509694379214")))

$client.query do
  get ref('classes/posts/104979509694379214')
end

client.Query(Get(Ref("classes/posts/104979509694379214")));

client.query(q.get(Ref("classes/posts/104979509694379214")))

client.Query(f.Get(f.Ref("classes/posts/104979509694379214")))

client.query(Get(Ref("classes/posts/104979509694379214")))

HTTP/1.1 200 OK
{
  "resource": {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

You can query for posts with a specific title using the match function and the index we created earlier:


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "get": {
            "match": { "index": "posts_by_title" },
            "terms": "My cat and other marvels"
          }
        }'

client.query(
  Get(
    Match(
      Index(Value("posts_by_title")),
      Value("My cat and other marvels"))));

client.query(
  q.Get(
    q.Match(
      q.Index("posts_by_title"),
      "My cat and other marvels")));

client.query(
  Get(
    Match(Index("posts_by_title"), "My cat and other marvels")))

$client.query do
  get match(index('posts_by_title'), 'My cat and other marvels')
end

client.Query(
  Get(
    Match(Index("posts_by_title"), "My cat and other marvels")));

client.query(
  q.get(
    q.match(
      q.index("posts_by_title"),
      "My cat and other marvels"
    )
  ))

client.Query(
    f.Get(
        f.MatchTerm(
            f.Index("posts_by_title"),
            "My cat and other marvels",
        ),
    ),
)

client.query(
    Get(
        Match(
            index: Index("posts_by_title"),
            terms: "My cat and other marvels"
        )
    )
)

HTTP/1.1 200 OK
{
  "resource": {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "My cat and other marvels" }
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "My cat and other marvels" }
}

The match function returns a logical set of elements, which can be combined with other sets with set-operations like join, intersect, subtract, etc.

Modifying Posts

You can easily modify instances by supplying the new data along with the reference to the instance. For example, you may want to add tags to each of your blog posts.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "update": { "@ref": "classes/posts/104979509694379214" },
          "params": {
            "object": { "data": { "object": { "tags": [ "pet", "cute" ] } } }
          }
        }'

client.query(
  Update(
    Ref("classes/posts/104979509694379214"),
    Obj("data", Obj("tags", Arr(Value("pet"), Value("cute"))))));

client.query(
  q.Update(
    Ref("classes/posts/104979509694379214"),
    { data: { tags: ["pet", "cute"] } }));

client.query(
  Update(
    Ref("classes/posts/104979509694379214"),
    Obj("data" -> Obj("tags" -> Arr("pet", "cute")))))

$client.query do
  update ref('classes/posts/104979509694379214'),
         data: { tags: ['pet', 'cute'] }
end

client.Query(
  Update(
    Ref("classes/posts/104979509694379214"),
    Obj("data", Obj("tags", Arr("pet", "cute")))));

client.query(
  q.update(
    Ref("classes/posts/104979509694379214"),
    {"data": {"tags": ["pet", "cute"]}}
  ))

client.Query(
    f.Update(
        f.Ref("classes/posts/104979509694379214"),
        f.Obj{"data": f.Obj{"tags": f.Arr{"pet", "cute"}}},
    ),
)

client.query(
    Update(
        ref: Ref("classes/posts/104979509694379214"),
        to: Obj("data" => Obj("tags" => Arr("pet", "cute")))
    )
)

HTTP/1.1 200 OK
{
  "resource": {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112548676,
    "data": {
      "title": "My cat and other marvels",
      "tags": [ "pet", "cute" ]
    }
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112548676,
  "data": {
    "title": "My cat and other marvels",
    "tags": [ "pet", "cute" ]
  }
}

The update function updates specific fields on an instance. It preserves the old fields if they are not specified in params. In the case of objects, the old and the new values are merged. If null is specified as a value for a field, it is removed.

The replace function, on the other hand, replaces the instance data with the fields provided in params. Therefore, old fields which are not mentioned in params are removed.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "replace": { "@ref": "classes/posts/104979509694379214" },
          "params": {
            "object": {
              "data": { "object": { "title": "My dog and other marvels" } }
            }
          }
        }'

client.query(
  Replace(
    Ref("classes/posts/104979509694379214"),
    Obj("data", Obj("title", Value("My dog and other marvels")))));

client.query(
  q.Replace(
    Ref("classes/posts/104979509694379214"),
    { data: { title: "My dog and other marvels" } }));

client.query(
  Replace(
    Ref("classes/posts/104979509694379214"),
    Obj("data" -> Obj("title" -> "My dog and other marvels"))))

$client.query do
  replace ref('classes/posts/104979509694379214'),
          data: { title: 'My dog and other marvels' }
end

client.Query(
  Replace(
    Ref("classes/posts/104979509694379214"),
    Obj("data", Obj("title", "My dog and other marvels"))));

client.query(
  q.replace(
    Ref("classes/posts/104979509694379214"),
    {"data": {"title": "My dog and other marvels"}}
  ))

client.Query(
    f.Replace(
        f.Ref("classes/posts/104979509694379214"),
        f.Obj{"data": f.Obj{"title": "My dog and other marvels"}},
    ),
)

client.query(
    Replace(
        ref: Ref("classes/posts/104979509694379214"),
        with: Obj(
            "data" => Obj("title" => "My dog and other marvels")
        )
    )
)

HTTP/1.1 200 OK
{
  "resource": {
    "ref": { "@ref": "classes/posts/104979509694379214" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112606838,
    "data": { "title": "My dog and other marvels" }
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509694379214" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112606838,
  "data": { "title": "My dog and other marvels" }
}

Note that the title has been updated, but the tags has been deleted.

Deleting a Post

Lastly, a post can be removed using the delete function:


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{ "delete": { "@ref": "classes/posts/104979509695900060" } }'

client.query(Delete(Ref("classes/posts/104979509695900060")));

client.query(q.Delete(Ref("classes/posts/104979509695900060")));

client.query(Delete(Ref("classes/posts/104979509695900060")))

$client.query do
  delete ref('classes/posts/104979509695900060')
end

client.Query(Delete(Ref("classes/posts/104979509695900060")));

client.query(q.delete(Ref("classes/posts/104979509695900060")))

client.Query(
    f.Delete(f.Ref("classes/posts/104979509695900060")),
)

client.query(
    Delete(ref: Ref("classes/posts/104979509695900060"))
)

HTTP/1.1 200 OK
{
  "resource": {
    "ref": { "@ref": "classes/posts/104979509695900060" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112490514,
    "data": { "title": "Deep meanings in a latte" }
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

=> {
  "ref": { "@ref": "classes/posts/104979509695900060" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112490514,
  "data": { "title": "Deep meanings in a latte" }
}

curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{ "get": { "@ref": "classes/posts/104979509695900060" } }'

client.query(Get(Ref("classes/posts/104979509695900060")));

client.query(q.Get(Ref("classes/posts/104979509695900060")));

client.query(Get(Ref("classes/posts/104979509695900060")))

$client.query do
  get ref('classes/posts/104979509695900060')
end

client.Query(Get(Ref("classes/posts/104979509695900060")));

client.query(q.get(Ref("classes/posts/104979509695900060")))

client.Query(f.Get(f.Ref("classes/posts/104979509695900060")))

client.query(Get(Ref("classes/posts/104979509695900060")))

HTTP/1.1 404 Not Found
{
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

=> {
  "errors": [
    {
      "position": [  ],
      "code": "instance not found",
      "description": "Instance not found."
    }
  ]
}

Iterating over Posts

Working with bulk data will require pagination of some sort. FaunaDB supports pagination in its query language and allows you to iterate over objects one page at a time. To understand pagination better, let’s update the post objects with some tags and use the index we created earlier, posts_by_tags_with_title to query for them.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "do": [
            {
              "update": { "@ref": "classes/posts/104979509694379214" },
              "params": {
                "object": {
                  "data": { "object": { "tags": [ "pet", "cute", "funny" ] } }
                }
              }
            },
            {
              "update": { "@ref": "classes/posts/104979509695139637" },
              "params": {
                "object": {
                  "data": { "object": { "tags": [ "philosophy", "travel" ] } }
                }
              }
            },
            {
              "create": { "class": "posts" },
              "params": {
                "object": {
                  "data": {
                    "object": {
                      "title": "Homebound",
                      "tags": [ "nostalgia", "travel" ]
                    }
                  }
                }
              }
            },
            {
              "create": { "class": "posts" },
              "params": {
                "object": {
                  "data": {
                    "object": {
                      "title": "All Aboard",
                      "tags": [ "ship", "travel" ]
                    }
                  }
                }
              }
            }
          ]
        }'

client.query(
  Do(
    Update(
      Ref("classes/posts/104979509694379214"),
      Obj(
        "data", Obj(
          "tags", Arr(Value("pet"), Value("cute"), Value("funny"))
        )
      )),
    Update(
      Ref("classes/posts/104979509695139637"),
      Obj(
        "data", Obj("tags", Arr(Value("philosophy"), Value("travel")))
      )),
    Create(
      Class(Value("posts")),
      Obj(
        "data", Obj(
          "title", Value("Homebound"),
          "tags", Arr(Value("nostalgia"), Value("travel"))
        )
      )),
    Create(
      Class(Value("posts")),
      Obj(
        "data", Obj(
          "title", Value("All Aboard"),
          "tags", Arr(Value("ship"), Value("travel"))
        )
      ))));

client.query(
  q.Do(
    q.Update(
      Ref("classes/posts/104979509694379214"),
      { data: { tags: ["pet", "cute", "funny"] } }),
    q.Update(
      Ref("classes/posts/104979509695139637"),
      { data: { tags: ["philosophy", "travel"] } }),
    q.Create(
      q.Class("posts"),
      {
        data: { title: "Homebound", tags: ["nostalgia", "travel"] }
      }),
    q.Create(
      q.Class("posts"),
      { data: { title: "All Aboard", tags: ["ship", "travel"] } })));

client.query(
  Do(
    Update(
      Ref("classes/posts/104979509694379214"),
      Obj("data" -> Obj("tags" -> Arr("pet", "cute", "funny")))),
    Update(
      Ref("classes/posts/104979509695139637"),
      Obj("data" -> Obj("tags" -> Arr("philosophy", "travel")))),
    Create(
      Class("posts"),
      Obj(
        "data" -> Obj(
          "title" -> "Homebound",
          "tags" -> Arr("nostalgia", "travel")
        )
      )),
    Create(
      Class("posts"),
      Obj(
        "data" -> Obj(
          "title" -> "All Aboard",
          "tags" -> Arr("ship", "travel")
        )
      ))))

$client.query do
  do_(
    update(ref('classes/posts/104979509694379214'),
           data: { tags: ['pet', 'cute', 'funny'] }),
    update(ref('classes/posts/104979509695139637'),
           data: { tags: ['philosophy', 'travel'] }),
    create(class_('posts'),
           data: { title: 'Homebound', tags: ['nostalgia', 'travel'] }),
    create(class_('posts'),
           data: { title: 'All Aboard', tags: ['ship', 'travel'] }))
end

client.Query(
  Do(
    Update(
      Ref("classes/posts/104979509694379214"),
      Obj("data", Obj("tags", Arr("pet", "cute", "funny")))),
    Update(
      Ref("classes/posts/104979509695139637"),
      Obj("data", Obj("tags", Arr("philosophy", "travel")))),
    Create(
      Class("posts"),
      Obj(
        "data", Obj(
          "title", "Homebound",
          "tags", Arr("nostalgia", "travel")
        )
      )),
    Create(
      Class("posts"),
      Obj(
        "data", Obj("title", "All Aboard", "tags", Arr("ship", "travel"))
      ))));

client.query(
  q.do(
    q.update(
      Ref("classes/posts/104979509694379214"),
      {"data": {"tags": ["pet", "cute", "funny"]}}
    ),
    q.update(
      Ref("classes/posts/104979509695139637"),
      {"data": {"tags": ["philosophy", "travel"]}}
    ),
    q.create(
      q.class_expr("posts"),
      {
        "data": {"title": "Homebound", "tags": ["nostalgia", "travel"]}
      }
    ),
    q.create(
      q.class_expr("posts"),
      {
        "data": {"title": "All Aboard", "tags": ["ship", "travel"]}
      }
    )
  ))

client.Query(
    f.Do(
        f.Update(
            f.Ref("classes/posts/104979509694379214"),
            f.Obj{
                "data": f.Obj{"tags": f.Arr{"pet", "cute", "funny"}},
            },
        ),
        f.Update(
            f.Ref("classes/posts/104979509695139637"),
            f.Obj{
                "data": f.Obj{"tags": f.Arr{"philosophy", "travel"}},
            },
        ),
        f.Create(
            f.Class("posts"),
            f.Obj{
                "data": f.Obj{
                    "title": "Homebound",
                    "tags": f.Arr{"nostalgia", "travel"},
                },
            },
        ),
        f.Create(
            f.Class("posts"),
            f.Obj{
                "data": f.Obj{
                    "title": "All Aboard",
                    "tags": f.Arr{"ship", "travel"},
                },
            },
        ),
    ),
)

client.query(
    Do(
        Update(
            ref: Ref("classes/posts/104979509694379214"),
            to: Obj(
                "data" => Obj("tags" => Arr("pet", "cute", "funny"))
            )
        ),
        Update(
            ref: Ref("classes/posts/104979509695139637"),
            to: Obj(
                "data" => Obj("tags" => Arr("philosophy", "travel"))
            )
        ),
        Create(
            at: Class("posts"),
            Obj(
                "data" => Obj(
                    "title" => "Homebound",
                    "tags" => Arr("nostalgia", "travel")
                )
            )
        ),
        Create(
            at: Class("posts"),
            Obj(
                "data" => Obj(
                    "title" => "All Aboard",
                    "tags" => Arr("ship", "travel")
                )
            )
        )
    )
)

HTTP/1.1 201 Created
{
  "resource": {
    "ref": { "@ref": "classes/posts/104979509696660483" },
    "class": { "@ref": "classes/posts" },
    "ts": 1436375112665000,
    "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
  }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

=> {
  "ref": { "@ref": "classes/posts/104979509696660483" },
  "class": { "@ref": "classes/posts" },
  "ts": 1436375112665000,
  "data": { "title": "All Aboard", "tags": [ "ship", "travel" ] }
}

The do function takes a sequence of function calls, evaluates them one after the other and returns the response from the last one.

Now, we can use the index posts_by_tags_with_title to fetch posts that match a given tag.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "paginate": {
            "match": { "index": "posts_by_tags_with_title" },
            "terms": "travel"
          },
          "size": 2
        }'

client.query(
  Paginate(
      Match(
        Index(Value("posts_by_tags_with_title")),
        Value("travel")))
    .size(Value(2)));

client.query(
  q.Paginate(
    q.Match(q.Index("posts_by_tags_with_title"), "travel"),
    { size: 2 }));

client.query(
  Paginate(
    Match(Index("posts_by_tags_with_title"), "travel"),
    size = 2))

$client.query do
  paginate match(index('posts_by_tags_with_title'), 'travel'),
           size: 2
end

client.Query(
  Paginate(
    Match(Index("posts_by_tags_with_title"), "travel"),
    size: 2));

client.query(
  q.paginate(
    q.match(q.index("posts_by_tags_with_title"), "travel"),
    size=2
  ))

client.Query(
    f.Paginate(
        f.MatchTerm(
            f.Index("posts_by_tags_with_title"),
            "travel",
        ),
        f.Size(2),
    ),
)

client.query(
    Paginate(
        Match(
            index: Index("posts_by_tags_with_title"),
            terms: "travel"
        ),
        size: 2
    )
)

HTTP/1.1 200 OK
{
  "resource": {
    "after": [
      "Pondering during a commute",
      { "@ref": "classes/posts/104979509695139637" }
    ],
    "data": [ "All Aboard", "Homebound" ]
  }
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

=> {
  "after": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "All Aboard", "Homebound" ]
}

The paginate function returns the first page of qualifying entries from the index. The size of the page is determined by the size parameter. You can move forward or backwards page by page using the after or before value as a cursor.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "paginate": {
            "match": { "index": "posts_by_tags_with_title" },
            "terms": "travel"
          },
          "after": [
            "Pondering during a commute",
            { "@ref": "classes/posts/104979509695139637" }
          ],
          "size": 2
        }'

client.query(
  Paginate(
      Match(
        Index(Value("posts_by_tags_with_title")),
        Value("travel")))
    .after(Arr(
      Value("Pondering during a commute"),
      Ref("classes/posts/104979509695139637")
    ))
    .size(Value(2)));

client.query(
  q.Paginate(
    q.Match(q.Index("posts_by_tags_with_title"), "travel"),
    {
      after: [
        "Pondering during a commute",
        Ref("classes/posts/104979509695139637")
      ],
      size: 2
    }));

client.query(
  Paginate(
    Match(Index("posts_by_tags_with_title"), "travel"),
    cursor = After(Arr(
      "Pondering during a commute",
      Ref("classes/posts/104979509695139637")
    )),
    size = 2))

$client.query do
  paginate match(index('posts_by_tags_with_title'), 'travel'),
           after: [
             'Pondering during a commute',
             ref('classes/posts/104979509695139637')
           ],
           size: 2
end

client.Query(
  Paginate(
    Match(Index("posts_by_tags_with_title"), "travel"),
    after: Arr(
      "Pondering during a commute",
      Ref("classes/posts/104979509695139637")
    ),
    size: 2));

client.query(
  q.paginate(
    q.match(q.index("posts_by_tags_with_title"), "travel"),
    after=[
      "Pondering during a commute",
      Ref("classes/posts/104979509695139637")
    ],
    size=2
  ))

client.Query(
    f.Paginate(
        f.MatchTerm(
            f.Index("posts_by_tags_with_title"),
            "travel",
        ),
        f.After(f.Arr{
            "Pondering during a commute",
            f.Ref("classes/posts/104979509695139637"),
        }),
        f.Size(2),
    ),
)

client.query(
    Paginate(
        Match(
            index: Index("posts_by_tags_with_title"),
            terms: "travel"
        ),
        after: Arr(
            "Pondering during a commute",
            Ref("classes/posts/104979509695139637")
        ),
        size: 2
    )
)

HTTP/1.1 200 OK
{
  "resource": {
    "before": [
      "Pondering during a commute",
      { "@ref": "classes/posts/104979509695139637" }
    ],
    "data": [ "Pondering during a commute" ]
  }
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

=> {
  "before": [
    "Pondering during a commute",
    { "@ref": "classes/posts/104979509695139637" }
  ],
  "data": [ "Pondering during a commute" ]
}

Since a page is also a collection in FaunaDB, collection functions can be used to process the elements further. Suppose, we wanted only the title of posts tagged with travel.


curl https://db.fauna.com/ \
    -u kqnPAi4gDivAAAC0i5t-a9YCcRnljtU2SfMJ-kWSRYI: \
    -d '{
          "map": {
            "lambda": "post",
            "expr": { "casefold": { "var": "post" } }
          },
          "collection": {
            "paginate": {
              "match": { "index": "posts_by_tags_with_title" },
              "terms": "travel"
            }
          }
        }'

client.query(
  Map(
    Paginate(
        Match(
          Index(Value("posts_by_tags_with_title")),
          Value("travel"))),
    Lambda(Value("post"), Casefold(Var("post")))));

client.query(
  q.Map(
    q.Paginate(
      q.Match(q.Index("posts_by_tags_with_title"), "travel")),
    function(post) {
      return q.Casefold(post);
    }));

client.query(
  Map(
    Paginate(Match(Index("posts_by_tags_with_title"), "travel")),
    Lambda { post => Casefold(post) }))

$client.query do
  map paginate(match(index('posts_by_tags_with_title'), 'travel')) do |post|
    casefold(post)
  end
end

client.Query(
  Map(
    Paginate(Match(Index("posts_by_tags_with_title"), "travel")),
    post => Casefold(post)));

client.query(
  q.map_expr(
    lambda post: q.casefold(post),
    q.paginate(
      q.match(q.index("posts_by_tags_with_title"), "travel")
    )
  ))

client.Query(
    f.Map(
        f.Paginate(
            f.MatchTerm(
                f.Index("posts_by_tags_with_title"),
                "travel",
            ),
        ),
        f.Lambda("post", f.Casefold(f.Var("post"))),
    ),
)

client.query(
    Map(
        collection: Paginate(
            Match(
                index: Index("posts_by_tags_with_title"),
                terms: "travel"
            )
        ),
        to: { post in Casefold(post) }
    )
)

HTTP/1.1 200 OK
{
  "resource": {
    "data": [ "all aboard", "homebound", "pondering during a commute" ]
  }
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

=> {
  "data": [ "all aboard", "homebound", "pondering during a commute" ]
}

The casefold function converts the given string to lowercase. The map function iterates this over the entire page of entries and returns only the titles from the pages.

Further Reading

This tutorial dealt with the simple case of creating a blog and associating some posts with it. You may want to delve into details with some of the advanced tutorials below: