Check out v4 of the Fauna CLI
v4 of the Fauna CLI is now in beta. The new version introduces enhancements to the developer experience, including an improved authentication workflow. To get started, check out the CLI v4 quick start. |
Projection and field aliasing
Projection allows you to select the fields to be returned and is supported
for Struct, Array, Set, and Document types.
If you apply projection to a type that doesn’t support projection, the
result is an object with the same shape as the projection request but all
field values are set to null
.
If a requested field doesn’t exist in the projected object, the returned
field value is set to null
.
Fields are returned in the order listed in the query.
Struct projection
The result of projection on a Struct returns a struct with only the requested fields extracted.
let customer = {
name: "John Doe",
email: "john.doe@example.com",
address: {
street: "123 Main St",
city: "San Francisco",
state: "CA",
postalCode: "12345",
country: "United States"
}
}
customer {
name,
email,
address {
street
}
}
{
name: "John Doe",
email: "john.doe@example.com",
address: {
street: "123 Main St"
}
}
Array projection
The result of projection on an Array is an Array with the projection applied to each element of the Array:
let stores = [
{
name: "DC Fruits",
address: {
street: "13 Pierstorff Drive",
city: "Washington",
state: "DC",
zipCode: "20220"
}
},
{
name: "Party Supplies",
address: {
street: "7529 Capitalsaurus Court",
city: "Washington",
state: "DC",
zipCode: "20002"
}
},
{
name: "Foggy Bottom Market",
address: {
street: "4 Florida Ave",
city: "Washington",
state: "DC",
zipCode: "20037"
}
}
]
stores {
name
}
[
{
name: "DC Fruits"
},
{
name: "Party Supplies"
},
{
name: "Foggy Bottom Market"
}
]
Set projection
The result of projection on a Set is a new Set where the field selections are applied to each element in the original Set. The result type on a Set is a Set.
For example:
Category.all() { name }
{
data: [
{
name: "party"
},
{
name: "frozen"
},
{
name: "produce"
}
]
}
You can also use the FQL set.map()
method to project Sets. For example, the following projection query:
Product.sortedByPriceLowToHigh() {
name,
description,
price
}
Is equivalent to the following
set.map()
query:
Product.sortedByPriceLowToHigh().map(prod => {
name: prod.name,
description: prod.description,
price: prod.price,
})
Document projection
Applying projection to a document, the projected fields are extracted directly from the document. The value returned from projection on a document is a Struct.
For example:
Category.byName("produce").first() { name }
{
name: "produce"
}
Traverse document references
You can use document references to create relationships between documents. The reference acts as a pointer to a document. The reference contains the document’s collection and document ID.
For example, the following query updates a Product
collection document to add
a category
field. The category
field contains a reference to a Category
collection document.
let produce = Category.byName("produce").first()
Product.byName("limes").first()
?.update({
category: produce
})
// An example `Product` collection document.
{
id: "777",
coll: Product,
ts: Time("2099-04-10T16:07:02.515Z"),
name: "limes",
description: "Conventional, 16 oz bag",
price: 299,
stock: 30,
// A `Category` document reference.
// The reference contains the document's
// collection and document ID.
category: Category("789")
}
When the category
field is projected, the reference is resolved and the full
Category
collection document is returned:
// Gets a `Product` document and projects the
// `name` and `category` fields.
Product.byName("limes").first() { name, category}
{
name: "limes",
// The projection resolves the `Category` document
// reference in the `category` field.
category: {
id: "789",
coll: Category,
ts: Time("2099-07-30T22:17:39.945Z"),
products: "hdW...",
name: "produce",
description: "Fresh Produce"
}
}
Traverse Set references
Sets are not persistable. You can’t store a Set as a field value or create a field definition that accepts a Set.
Instead, you can use a computed field to define a read-only function that dynamically fetches a Set:
collection Customer {
...
// Computed field definition for the `orders` field.
// `orders` contains a reference to a Set of `Order` collection documents.
// The value is computed using the `Order` collection's
// `byCustomer()` index to get the customer's orders.
compute orders: Set<Order> = ( customer => Order.byCustomer(customer))
...
}
If the field isn’t projected, it contains an
after
pagination cursor that
references the Set:
// Get a `Customer` document.
Customer.byEmail("alice.appleseed@example.com").first()
{
id: "111",
coll: Customer,
ts: Time("2099-10-22T21:56:31.260Z"),
cart: Order("412483941752112205"),
// `orders` contains an `after` cursor that
// references the Set of `Order` documents.
orders: "hdW...",
name: "Alice Appleseed",
email: "alice.appleseed@example.com",
address: {
street: "87856 Mendota Court",
city: "Washington",
state: "DC",
postalCode: "20220",
country: "US"
}
}
To materialize the Set, project the computed field:
let customer = Customer
.where(.email == "alice.appleseed@example.com")
.first()
// Project the `name`, `email`, and `orders` fields.
customer {
name,
email,
orders
}
{
name: "Alice Appleseed",
email: "alice.appleseed@example.com",
orders: {
data: [
{
id: "412483941752112205",
coll: Order,
ts: Time("2099-10-22T21:56:31.260Z"),
items: "hdW...",
total: 5392,
status: "cart",
customer: Customer("111"),
createdAt: Time("2099-10-22T21:56:31.104083Z"),
payment: {}
},
...
]
}
}
Alternatively, you can pass the after
cursor to
Set.paginate()
:
Set.paginate("hdW...", 2)
{
// Returns a materialized Set of `Order` documents.
data: [
{
id: "412483941752112205",
coll: Order,
ts: Time("2099-10-22T21:56:31.260Z"),
items: "hdW...",
total: 5392,
status: "cart",
customer: Customer("111"),
createdAt: Time("2099-10-22T21:56:31.104083Z"),
payment: {}
},
...
]
}
Field aliasing
Referencing fields can be simplified when working with projected fields, including nested fields, by defining an alias using field accessors. A field alias gives you a shortcut for referencing fields and field combinations.
Example projecting a nested field:
-
Given the following document:
Customer.byEmail("alice.appleseed@example.com").first()
{ id: "111", coll: Customer, ts: Time("2099-06-25T12:14:29.440Z"), cart: Order("412653216549831168"), orders: "hdW...", name: 'Alice Appleseed', email: 'alice.appleseed@example.com', address: { street: '87856 Mendota Court', city: 'Washington', state: 'DC', postalCode: '20220', country: 'US' } }
-
Define an alias using dot notation to get the value of the projected field:
Customer.byEmail("alice.appleseed@example.com").first() { myCity: .address.city }
{ myCity: "Washington" }
Example projecting multiple fields:
-
Given the following document:
Customer.byEmail("alice.appleseed@example.com").first()
{ id: "111", coll: Customer, ts: Time("2099-06-25T12:14:29.440Z"), cart: Order("412653216549831168"), orders: "hdW...", name: 'Alice Appleseed', email: 'alice.appleseed@example.com', address: { street: '87856 Mendota Court', city: 'Washington', state: 'DC', postalCode: '20220', country: 'US' } }
-
Define an alias that references multiple fields to get the value of the projected field:
Customer.byEmail("alice.appleseed@example.com").first() { cityState: .address.city + ", " + .address.state }
{ cityState: "Washington, DC" }
Is this article helpful?
Tell Fauna how the article can be improved:
Visit Fauna's forums
or email docs@fauna.com
Thank you for your feedback!