Range

This reference topic applies to FQL v4. Go to this page for the latest FQL v10 reference topics.

Range( set, start, end )
Range( set, start, end )
Range( set, start, end )
range( set, start, end )
Range( set, start, end )

Description

The Range function returns an inclusive subset of the values from the provided set that includes the range of values starting from start up to (and including) end, as defined by the order of the set.

For the set of letters, in ascending order, setting start to F and end to M results in the subset of letters including F to M:

The range in a set with ascending order

For the set of letters, in descending order, setting start to M and end to F results in the subset of letters including M to F:

The range in a set with descending order

Items in the set can be:

  • single, scalar values

  • tuples containing a variety of values of different types

start and end are expressed as prefixes that need to match some, or all, of the structure provided by the set, or Range returns an empty set. Prefix-based matching means that, if your set contains two or more fields, you only need to specify the first field in start or end to achieve a match. You may have to specify additional fields if there are multiple entries in the set that would match the first field.

For example, if an index’s values field contains last and first fields, start or end can be expressed as just a last name, or an array containing the last and first names to mark a boundary of the range.

When start or end match an entry in the set, that’s where the boundary for the range is set; no further evaluation is done.

Both start and end can be expressed as an empty array, which indicates that the range should extend to, respectively, the set’s first item, or the set’s last item. If both start and end are expressed as an empty arrange, the entire range is returned.

Parameters

Parameter Type Definition and Requirements

set

Set

The Set of items to process.

start

Value, or Array of Values

The Value(s) marking the start of the range to return. start is inclusive.

Use an empty Array to indicate that start should start with the first item in set.

end

Value, or Array of Values

The Value(s) marking the end of the range to return. end is inclusive.

Use an empty Array to indicate that to should end with the last item in set.

Returns

A new Set containing values from set in the range between from and to inclusive.

Examples

With a collection containing the letters of the alphabet, and an index with a values field defined to contain each document’s letter field, the following query returns the range of values from F to M:

try
{
    Value result = await client.Query(
        Paginate(
            Range(Match(Index("letters")), "F", "M")
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
ObjectV(data: Arr(StringV(F), StringV(G), StringV(H), StringV(I), StringV(J), StringV(K), StringV(L), StringV(M)))
result, err := client.Query(
	f.Paginate(
		f.Range(
			f.Match(
				f.Index("letters")),
				"F", "M")))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
map[data:[F G H I J K L M]]
client.query(
  q.Paginate(
    q.Range(q.Match(q.Index('letters')), 'F', 'M')
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{ data: [ 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M' ] }
result = client.query(
  q.paginate(
    q.range(q.match(q.index("letters")), "F", "M")
  )
)
print(result)
{'data': ['F', 'G', 'H', 'I', 'J', 'K', 'L', 'M']}
Paginate(
  Range(Match(Index('letters')), 'F', 'M')
)
{ data: [
    'F', 'G', 'H',
    'I', 'J', 'K',
    'L', 'M'
  ] }
Query metrics:
  •    bytesIn:   83

  •   bytesOut:   55

  • computeOps:    1

  •    readOps:    8

  •   writeOps:    0

  •  readBytes:  488

  • writeBytes:    0

  •  queryTime: 13ms

  •    retries:    0

With the same setup, the following query returns all of the letters up to, and including, M:

try
{
    Value result = await client.Query(
        Paginate(
            Range(Match(Index("letters")), Arr(), "M")
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
ObjectV(data: Arr(StringV(A), StringV(B), StringV(C), StringV(D), StringV(E), StringV(F), StringV(G), StringV(H), StringV(I), StringV(J), StringV(K), StringV(L), StringV(M)))
result, err := client.Query(
	f.Paginate(
		f.Range(
			f.Match(f.Index("letters")), f.Arr{}, "M")))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
map[data:[A B C D E F G H I J K L M]]
client.query(
  q.Paginate(
    q.Range(q.Match(q.Index('letters')), [], 'M')
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{ data:
   [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M' ] }
result = client.query(
  q.paginate(
    q.range(q.match(q.index("letters")), [], "M")
  )
)
print(result)
{'data': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M']}
Paginate(
  Range(Match(Index('letters')), [], 'M')
)
{
  data: [
    'A', 'B', 'C', 'D',
    'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L',
    'M'
  ]
}
Query metrics:
  •    bytesIn:   82

  •   bytesOut:   75

  • computeOps:    1

  •    readOps:    8

  •   writeOps:    0

  •  readBytes:  708

  • writeBytes:    0

  •  queryTime: 14ms

  •    retries:    0

With the same setup, the following query returns F and all of the subsequent letters:

try
{
    Value result = await client.Query(
        Paginate(
            Range(Match(Index("letters")), "F", Arr())
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
ObjectV(data: Arr(StringV(F), StringV(G), StringV(H), StringV(I), StringV(J), StringV(K), StringV(L), StringV(M), StringV(N), StringV(O), StringV(P), StringV(Q), StringV(R), StringV(S), StringV(T), StringV(U), StringV(V), StringV(W), StringV(X), StringV(Y), StringV(Z)))
result, err := client.Query(
	f.Paginate(
		f.Range(
			f.Match(
				f.Index("letters")),
				"F", f.Arr{})))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
map[data:[F G H I J K L M N O P Q R S T U V W X Y Z]]
client.query(
  q.Paginate(
    q.Range(q.Match(q.Index('letters')), 'F', [])
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{ data:
   [ 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ] }
result = client.query(
  q.paginate(
    q.range(q.match(q.index("letters")), "F", [])
  )
)
print(result)
{'data': ['F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']}
Paginate(
  Range(Match(Index('letters')), 'F', [])
)
{
  data: [
    'F', 'G', 'H', 'I', 'J',
    'K', 'L', 'M', 'N', 'O',
    'P', 'Q', 'R', 'S', 'T',
    'U', 'V', 'W', 'X', 'Y',
    'Z'
  ]
}
Query metrics:
  •    bytesIn:    82

  •   bytesOut:   107

  • computeOps:     1

  •    readOps:     8

  •   writeOps:     0

  •  readBytes: 1,060

  • writeBytes:     0

  •  queryTime:  14ms

  •    retries:     0

The schema setup is not documented here. Most of what you need to make this example work is included in the Index tutorials, including the creation of the collection and the creation of the letters documents. You would need to create an appropriate index, which should look like this:

{ ref: Index("letters"),
  ts: 1566580712100000,
  active: true,
  serialized: true,
  name: 'letters',
  source: Collection("Letters"),
  values: [ { field: [ 'data', 'letter' ] } ],
  partitions: 8 }

With a collection containing people, with first and last names, and an index with a values field defined to contain the last and first fields, the following query returns all of the people from Hopper to Minsky:

try
{
    Value result = await client.Query(
        Paginate(
            Range(
                Match(Index("people_by_last_first")), "Hopper", "Minsky"
            )
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
ObjectV(data: Arr(Arr(StringV(Hopper), StringV(Grace)), Arr(StringV(Lamport), StringV(Leslie)), Arr(StringV(Minsky), StringV(Marvin))))
result, err := client.Query(
	f.Paginate(
		f.Range(
			f.Match(
				f.Index("people_by_last_first")),
				"Hopper", "Minksy")))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
map[data:[[Hopper Grace] [Lamport Leslie]]]
client.query(
  q.Paginate(
    q.Range(
      q.Match(q.Index('people_by_last_first')), 'Hopper', 'Minsky'
    )
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{ data:
   [ [ 'Hopper', 'Grace' ],
     [ 'Lamport', 'Leslie' ],
     [ 'Minsky', 'Marvin' ] ] }
result = client.query(
  q.paginate(
    q.range(
      q.match(q.index("people_by_last_first")), "Hopper", "Minsky"
    )
  )
)
print(result)
{'data': [['Hopper', 'Grace'], ['Lamport', 'Leslie'], ['Minsky', 'Marvin']]}
Paginate(
  Range(
    Match(Index('people_by_last_first')), 'Hopper', 'Minsky'
  )
)
{
  data: [
    [ 'Hopper', 'Grace' ],
    [ 'Lamport', 'Leslie' ],
    [ 'Minsky', 'Marvin' ]
  ]
}
Query metrics:
  •    bytesIn:  106

  •   bytesOut:   83

  • computeOps:    1

  •    readOps:    8

  •   writeOps:    0

  •  readBytes:  304

  • writeBytes:    0

  •  queryTime: 18ms

  •    retries:    0

See the Index tutorials for the setup of the People collection. You would need to create an appropriate index, which should look like this:

{ ref: Index("people_by_last_first"),
  ts: 1570226020940000,
  active: true,
  serialized: true,
  name: 'people_by_last_first',
  source: Collection("People"),
  values:
   [ { field: [ 'data', 'last' ] },
     { field: [ 'data', 'first' ] } ],
  partitions: 8 }

With a collection containing people, with age, and first and last names, and an index with a values field defined to contain the age and first fields, the following query returns all of the people from 80, Leslie to 92, Marvin:

try
{
    Value result = await client.Query(
        Paginate(
            Range(
                Match(Index("people_by_age_first")),
                Arr(80, "Leslie"),
                Arr(92, "Marvin")
            )
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
ObjectV(data: Arr(Arr(LongV(80), StringV(Leslie)), Arr(LongV(81), StringV(Stephen)), Arr(LongV(92), StringV(Marvin))))
result, err := client.Query(
	f.Paginate(
		f.Range(
			f.Match(
				f.Index("people_by_age_first")),
				f.Arr{80, "Leslie"},
				f.Arr{92, "Marvin"})))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
map[data:[[80 Leslie] [81 Stephen] [92 Marvin]]]
client.query(
  q.Paginate(
    q.Range(
      q.Match(q.Index('people_by_age_first')),
      [80, 'Leslie'],
      [92, 'Marvin'],
    )
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{ data: [ [ 80, 'Leslie' ], [ 81, 'Stephen' ], [ 92, 'Marvin' ] ] }
result = client.query(
  q.paginate(
    q.range(
      q.match(q.index("people_by_age_first")),
      [80, "Leslie"],
      [92, "Marvin"],
    )
  )
)
print(result)
{'data': [[80, 'Leslie'], [81, 'Stephen'], [92, 'Marvin']]}
Paginate(
  Range(
    Match(Index('people_by_age_first')),
    [80, 'Leslie'],
    [92, 'Marvin'],
  )
)
{ data: [ [ 80, 'Leslie' ], [ 81, 'Stephen' ], [ 92, 'Marvin' ] ] }
Query metrics:
  •    bytesIn:  115

  •   bytesOut:   66

  • computeOps:    1

  •    readOps:    8

  •   writeOps:    0

  •  readBytes:  290

  • writeBytes:    0

  •  queryTime: 15ms

  •    retries:    0

If we repeat the query, but only use the person’s age in the range, the same result is returned:

try
{
    Value result = await client.Query(
        Paginate(
            Range(
                Match(Index("people_by_age_first")),
                Arr(80),
                Arr(92)
            )
        )
    );
    Console.WriteLine(result);
}
catch (Exception e)
{
    Console.WriteLine($"ERROR: {e.Message}");
}
ObjectV(data: Arr(Arr(LongV(80), StringV(Leslie)), Arr(LongV(81), StringV(Stephen)), Arr(LongV(92), StringV(Marvin))))
result, err := client.Query(
	f.Paginate(
		f.Range(
			f.Match(
				f.Index("people_by_age_first")),
				f.Arr{80},
				f.Arr{92})))

if err != nil {
	fmt.Fprintln(os.Stderr, err)
} else {
	fmt.Println(result)
}
map[data:[[80 Leslie] [81 Stephen] [92 Marvin]]]
client.query(
  q.Paginate(
    q.Range(
      q.Match(q.Index('people_by_age_first')),
      [80],
      [92],
    )
  )
)
.then((ret) => console.log(ret))
.catch((err) => console.error(
  'Error: [%s] %s: %s',
  err.name,
  err.message,
  err.errors()[0].description,
))
{ data: [ [ 80, 'Leslie' ], [ 81, 'Stephen' ], [ 92, 'Marvin' ] ] }
result = client.query(
  q.paginate(
    q.range(
      q.match(q.index('people_by_age_first')),
      [80],
      [92],
    )
  )
)
print(result)
{'data': [[80, 'Leslie'], [81, 'Stephen'], [92, 'Marvin']]}
Paginate(
  Range(
    Match(Index('people_by_age_first')),
    [80],
    [92],
  )
)
{ data: [ [ 80, 'Leslie' ], [ 81, 'Stephen' ], [ 92, 'Marvin' ] ] }
Query metrics:
  •    bytesIn:   97

  •   bytesOut:   66

  • computeOps:    1

  •    readOps:    8

  •   writeOps:    0

  •  readBytes:  290

  • writeBytes:    0

  •  queryTime: 14ms

  •    retries:    0

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!