Project

A query gives rows, and ordering arranges them. project shapes each row into the document that the caller needs. The caller receives that document without a second assembly step.

The examples start from Ada, Bob and Cy. They also add Grace as Ada's manager. A reference points to an existing entity, so create Grace first:

json43 B
{
  "#_grace": {
    "name": "Grace"
  }
}

The first commit returns Grace's ID, 1, in this fresh database. The next patch creates Ada, Bob and Cy with IDs 3, 4 and 5. Ada's manager references Grace:

json313 B
{
  "#_ada": {
    "name": "Ada",
    "role": "engineer",
    "age": 36,
    "manager": {
      "#link": 1
    }
  },
  "#_bob": {
    "name": "Bob",
    "role": "engineer",
    "age": 41,
    "mentor": {
      "#link": "#_ada"
    }
  },
  "#_cy": {
    "name": "Cy",
    "role": "designer",
    "age": 29
  }
}

Root and fields

project has root and fields members. root is an expression that gives the entity to read for each row. fields is the shape of the output, and it cannot be empty.

json386 B
{
  "find": [
    "?e"
  ],
  "where": [
    [
      "?e",
      "name",
      "Ada"
    ],
    [
      "?e",
      "age",
      "?v"
    ]
  ],
  "project": {
    "root": "?e",
    "fields": {
      "who": ".name",
      "boss": ".manager.name",
      "missing": ".unknown",
      "info": {
        "doubled": [
          "*",
          "?v",
          2
        ]
      }
    }
  }
}

The query selects Ada and gives one row:

Result / 111 B
[
  {
    "who": "Ada",
    "boss": "Grace",
    "missing": null,
    "info": {
      "doubled": 72
    }
  }
]

Field kinds

The value determines the field kind.

ValueKindResult
Text that starts with .PathReads that field of the root entity
An objectFieldsA nested shape with its own fields
Anything elseExpressionAn expression for each row

A path follows entity references, so .manager.name reads the name of the entity that manager refers to. A path that reaches nothing gives null instead of an error, as .unknown does above.

A nested object gives a nested document. An expression reads the row's variables, so info.doubled doubles ?v from the where clause.

Building text

An expression field builds text with format. The template comes first, and each {} accepts the next argument.

json346 B
{
  "find": [
    "?e"
  ],
  "where": [
    [
      "?e",
      "name",
      "Ada"
    ],
    [
      "?e",
      "age",
      "?v"
    ],
    [
      "?e",
      "name",
      "?n"
    ]
  ],
  "project": {
    "root": "?e",
    "fields": {
      "label": [
        "format",
        "{} is {}",
        "?n",
        "?v"
      ]
    }
  }
}
Result / 36 B
[
  {
    "label": "Ada is 36"
  }
]

An argument is an expression, never a path. A path reads a field only as the whole value of a field, so .name inside format gives the text .name. The query above binds ?n in where, which is how a field of the root entity reaches a template.

Names and paths

A field name cannot be empty, and it cannot start with $. Each segment of a path must be a name, so .. and a trailing . are errors. A segment cannot use the reserved array storage prefix stardust/list/.

json85 B
{
  "project": {
    "root": "?e",
    "fields": {
      "who": ".name."
    }
  }
}

Error

Invalid_Project

The path .name. ends with an empty segment. .name reads that field, and .manager.name follows the reference in manager to read a field of another entity.

Result mode

project selects positional rows when the query does not have resultMode. You can also set resultMode positional.

resultMode object and project give two shapes for one row. A query that contains both gives an error.

json253 B
{
  "find": [
    "?e"
  ],
  "where": [
    [
      "?e",
      "name",
      "Ada"
    ],
    [
      "?e",
      "age",
      "?v"
    ]
  ],
  "resultMode": "object",
  "project": {
    "root": "?e",
    "fields": {
      "who": ".name"
    }
  }
}

Error

Project_Result_Mode_Conflict

Project and page limits

A projected shape is not a page boundary, so project and page together are an error.

json287 B
{
  "find": [
    "?e"
  ],
  "where": [
    [
      "?e",
      "name",
      "Ada"
    ],
    [
      "?e",
      "age",
      "?v"
    ]
  ],
  "orderBy": [
    "?v"
  ],
  "page": {
    "size": 1
  },
  "project": {
    "root": "?e",
    "fields": {
      "who": ".name"
    }
  }
}

Error

Invalid_Page

A projection reads the current document of each entity, so project with a temporal read is also an error.

Run it

database query · query run.