Product SiteDocumentation Site

10.2. For Clauses

For clauses allow iteration on a sequence.
For each incoming tuple, the expression in the for clause is evaluated to a sequence. Each item in this sequence is in turn bound to the for variable. A tuple is hence produced for each incoming tuple, and for each item in the sequence produced by the for clause for this tuple.
For example, the following for clause:
for $x in 1 to 3
...
produces the following stream of tuples. The tuples themselves are for explanatory purposes, they are not part of the data model. The syntax is also ad-hoc and is used for illustrating.
$x : 1
$x : 2
$x : 3
The order in which items are bound by the for clause can be relaxed with unordered expressions, as described later in this section.
The following query, using a for and a return clause, is the counterpart of SQL's "SELECT display_name FROM answers". $x is bound in turn to each item in the answers collection.
Example 10.1. A for clause.
for $x in collection("answers")
return $x.owner.display_name
Results:
"Ubiguchi"
"Rob Wells"
"Victor Nicollet"
"descent89"
"JasonSmith"
"JasonSmith"
"JasonSmith"
"JasonSmith"

For clause expressions are composable, there can be several of them.
Example 10.2. Two for clauses.
for $x in ( 1, 2, 3 )
for $y in ( 1, 2, 3 )
return 10 * $x + $y
Results:
11
12
13
21
22
23
31
32
33

Example 10.3. A for clause with two variables.
for $x in ( 1, 2, 3 ), $y in ( 1, 2, 3 )
return 10 * $x + $y
Results:
11
12
13
21
22
23
31
32
33

A for variable is visible to subsequent bindings.
Example 10.4. Two for clauses.
for $x in ( [ 1, 2, 3 ],
            [ 4, 5, 6 ],
            [ 7, 8, 9 ] ),
    $y in $x[]
return $y,
for $x in collection("faqs")[size($$.tags) eq 5],
    $y in $x.tags[]
return {
  "id" : $x.question_id,
  "tag" : $y
}
Results:
1
2
3
4
5
6
7
8
9
{
  "id" : 5453872,
  "tag" : "database"
}
{
  "id" : 5453872,
  "tag" : "full-text-search"
}
{
  "id" : 5453872,
  "tag" : "nosql"
}
{
  "id" : 5453872,
  "tag" : "couchdb"
}
{
  "id" : 5453872,
  "tag" : "riak"
}

It is also possible to bind the position of the current item in the sequence to a variable.
Example 10.5. A for clause with a position variable.
for $x at $position in collection("answers")
return {
  "old id" : $x.answer_id,
  "new id" : $position
}
Results:
{
  "old id" : 37841,
  "new id" : 1
}
{
  "old id" : 37844,
  "new id" : 2
}
{
  "old id" : 4419542,
  "new id" : 3
}
{
  "old id" : 4419578,
  "new id" : 4
}
{
  "old id" : 4720977,
  "new id" : 5
}
{
  "old id" : 5454583,
  "new id" : 6
}
{
  "old id" : 6195094,
  "new id" : 7
}
{
  "old id" : 6210422,
  "new id" : 8
}

JSONiq supports joins. For example, the counterpart of "SELECT q.title AS question, q.question_id FROM faq q JOIN answers a ON q.question_id = a.question_id" is:
Example 10.6. A regular join.
for $question in collection("faqs"),
    $answer in collection("answers")
    [ $$.question_id eq $question.question_id ]
return { "question" : $question.title,
         "answer score" : $answer.score }
Results:
{
  "question" : "MySQL and NoSQL: Help me to choose the righ
t one",
  "answer score" : 17
}
{
  "question" : "MySQL and NoSQL: Help me to choose the righ
t one",
  "answer score" : 1
}
{
  "question" : "Redis, CouchDB or Cassandra?",
  "answer score" : 34
}
{
  "question" : "Full-text search in NoSQL databases",
  "answer score" : 6
}
{
  "question" : "Find CouchDB docs missing an arbitrary fiel
d",
  "answer score" : 0
}
{
  "question" : "Find CouchDB docs missing an arbitrary fiel
d",
  "answer score" : 1
}

Note how JSONiq handles semi-structured data in a flexible way.
Outer joins are also possible with "allowing empty", i.e., output will also be produced if there is no matching answer for a question. The following query is the counterpart of "SELECT q.title AS question, q.question_id FROM faq q LEFT JOIN answers a ON q.question_id = a.question_id".
Example 10.7. An outer join.
for $question in collection("faqs"),
    $answer allowing empty in collection("answers")
    [ $$.question_id eq $question.question_id ]
return { "question" : $question.title,
         "answer score" : $answer.score }
Results:
{
  "question" : "MySQL and NoSQL: Help me to choose the righ
t one",
  "answer score" : 17
}
{
  "question" : "MySQL and NoSQL: Help me to choose the righ
t one",
  "answer score" : 1
}
{
  "question" : "The Next-gen Databases",
  "answer score" : null
}
{
  "question" : "Redis, CouchDB or Cassandra?",
  "answer score" : 34
}
{
  "question" : "Full-text search in NoSQL databases",
  "answer score" : 6
}
{
  "question" : "Find CouchDB docs missing an arbitrary fiel
d",
  "answer score" : 0
}
{
  "question" : "Find CouchDB docs missing an arbitrary fiel
d",
  "answer score" : 1
}