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.

set.forEach()

Run a provided function on each element of a Set. Can perform writes.

Signature

forEach(callback: (A => Any)) => Null

Description

Iterates over all elements in the Set and executes a provided callback function on each element. It is used for mutations or writing documents based on each Set element.

Eager loading

This method uses eager loading and requires a read of each document in the calling Set. For large Sets, this may result in poor performance and high costs.

Performance hint: full_set_read

Queries that call this method on a document Set emit a performance hint, if enabled. For example, the following query:

// Use `forEach()` to increment each product's
// stock count by 1.
Product.all().forEach(
  doc => doc.stock + 1
)

Emits the following hint:

performance_hint: full_set_read - Using forEach() causes the full set to be read. See https://docs.fauna.com/performance_hint/full_set_read.
at *query*:3:22
  |
3 |   Product.all().forEach(
  |  ______________________^
4 | |   doc => doc.stock + 1
5 | | )
  | |_^
  |

To address the hint, use set.take() to explicitly limit the size of the calling Set to fewer than 100 documents:

// Limit the doc Set's size using `take()`
Product.all().take(20).forEach(
  doc => doc.stock + 1
)

This applies even if the original, unbounded Set contains fewer than 100 documents.

Alternatively, you can rewrite the query to avoid calling the method.

Avoid use on large sets

This method scans the full Set, which can cause many reads and might time out for large Sets.

Iterator methods

FQL provides several methods for iterating over a Set. set.forEach(), set.map(), set.flatMap() are similar but used for different purposes:

Method Primary use Notes

Perform in-place writes on Set elements.

Doesn’t return a value.

Returns a new Set.

Can’t perform writes.

Similar to set.map(), but flattens the resulting Set by one level.

Can’t perform writes.

For examples, see:

Parameters

Parameter Type Required Description

callback

Function

Yes

Anonymous FQL function to call on each element of the Set. Each call returns Null.

Return value

Type Description

Null

This method always returns Null.

Examples

Basic example

// Get a Set of `Customer` collection documents with an
// `address` in the `state` of `DC`.
let customers = Customer.where(.address?.state == "DC")
// Use `forEach()` to update each document in the previous Set.
customers.forEach(doc => doc.update({
  address: {
    street: doc?.address?.street,
    city: doc?.address?.city,
    state: "District of Columbia",
    postalCode: doc?.address?.postalCode,
    country: doc?.address?.country,
  }
})) // `forEach()` returns `null`.
null

Although it returns null, set.forEach() still performed the requested operations. To verify:

// Get all `Customer` collection documents
Customer.all()
  // The results contain `Customer` documents updated by
  // the previous `forEach()` call.
{
  data: [
    {
      id: "111",
      coll: Customer,
      ts: Time("2099-10-02T21:50:14.555Z"),
      cart: Order("410671593745809485"),
      orders: "hdW...",
      name: "Alice Appleseed",
      email: "alice.appleseed@example.com",
      address: {
        street: "87856 Mendota Court",
        city: "Washington",
        state: "District of Columbia", // `state` has been updated.
        postalCode: "20220",
        country: "US"
      }
    },
    ...
  ]
}

set.forEach() vs. set.map()

You can use both set.forEach() and set.map() to iterate through a Set.

Use set.forEach() to perform in-place writes on the calling Set:

// Gets the frozen category.
let frozen = Category.byName("frozen").first()

// Uses `forEach()` to delete each product in
// the frozen category.
Product.byCategory(frozen).forEach(product => {
  product.delete()
})
null

Although it returns null, set.forEach() still performs the requested operations.

Unlike set.forEach(), set.map() can’t perform writes:

// Gets the produce category.
let produce = Category.byName("produce").first()

// Attempts to use `map()` to delete each product in
// the produce category.
Product.byCategory(produce).map(product => {
  product.delete()
})
invalid_effect: `delete` performs a write, which is not allowed in set functions.

error: `delete` performs a write, which is not allowed in set functions.
at *query*:7:17
  |
7 |   product.delete()
  |                 ^^
  |

Instead, you can use set.map() to output a new Set containing extracted or transformed values:

// Gets the produce category.
let produce = Category.byName("produce").first()

// Uses `map()` to outputs a new Set containing products in
// the produce category. The new Set transforms each product's
// name.
Product.byCategory(produce).map(product => {
  let product: Any = product
  {
    name: product.category.name + ": " + product.name,
  }
})
{
  data: [
    {
      name: "produce: avocados"
    },
    {
      name: "produce: single lime"
    },
    {
      name: "produce: organic limes"
    },
    {
      name: "produce: limes"
    },
    {
      name: "produce: cilantro"
    }
  ]
}

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!