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: Any = 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!