Projections for collections
Certain document operations, such as findOne
, find
, findOneAndUpdate
, findOneAndReplace
, and findOneAndDelete
, support a projection
option that specifies which part of a document to return.
Typically, the projection specifies which fields to include or exclude.
If projection
is empty or unspecified, the Data API applies the default projection.
For documents, the default projection includes, at minimum, the document identifier (_id
) and all regular fields, which are fields not prefixed by a dollar sign ($
).
If you specify a projection, all special fields, such as _id
, $vector
, and $vectorize
, have specific inclusion and exclusion defaults that you can override individually.
However, for regular fields, the projection must either include or exclude those fields.
The projection can’t define a mix of included and excluded regular fields.
If a projection includes fields that don’t exist in a returned document, then those fields are ignored for that document.
In order to optimize the response size and improve read performance, DataStax recommends always providing an explicit projection tailored to the needs of the application. If an application relies on the presence of A quick, but possibly suboptimal, way to ensure the presence of special fields is to use the wildcard projection |
Projection syntax
A projection is expressed as a mapping of field names to boolean values.
Use true
mapping to include only the specified fields.
For example, the following true
mapping returns the document ID, field1
, and field2
:
{ "_id": true, "field1": true, "field2": true }
Alternatively, use a false
mapping to exclude the specified fields.
All other non-excluded fields are returned.
{ "field1": false, "field2": false }
The values in a projection map can be objects, booleans, decimals, or integers, but the Data API ultimately evaluates all of these as booleans.
For example, the following projection evaluates to true
(include) for all four fields:
{ "field1": true, "field2": 1, "field3": 90.0, "field4": { "keep": "yes!" } }
Whereas this projection evaluates to false
(exclude) for all four fields:
{ "field1": false, "field2": 0, "field3": 0.0, "field4": {} }
Passing null-like types (such as {}
, null
or 0
) for the whole projection
mapping is equivalent to omitting projection
.
Projecting regular and special fields
For regular fields, a projection can’t mix include and exclude projections.
It can contain only true
or only false
values for regular fields.
For example, {"field1": true, "field2": false}
is an invalid projection that results in an API error.
However, the special fields _id
, $vector
, and $vectorize
have individual default inclusion and exclusion rules, regardless of the projection mapping.
Unlike regular fields, you can set the projection values for special fields independently of regular fields:
-
The
_id
field is included by default. You can opt to exclude it in atrue
mapping, such as{ "_id": false, "field1": true }
. -
The
$vector
and$vectorize
fields are excluded by default. You can opt to include these in afalse
mapping, such as{ "field1": false, "$vector": true }
. -
The
$similarity
key isn’t a document field, and you can’t use this key in a projection. The$similarity
value is the result of a vector search operation with$vector
or$vectorize
. Use theincludeSimilarity
parameter to control the presence of$similarity
in the response.
Therefore, the following are all valid projections for regular and special fields:
{ "_id": true, "field1": true, "field2": true }
{ "_id": false, "field1": true, "field2": true }
{ "_id": false, "field1": false, "field2": false }
{ "_id": true, "field1": false, "field2": false }
{ "_id": true, "field1": true, "field2": true, "$vector": true }
{ "_id": true, "field1": true, "field2": true, "$vector": false }
{ "_id": false, "field1": true, "field2": true, "$vector": true }
{ "_id": false, "field1": true, "field2": true, "$vector": false }
{ "_id": false, "field1": false, "field2": false, "$vector": true }
{ "_id": false, "field1": false, "field2": false, "$vector": false }
{ "_id": true, "field1": false, "field2": false, "$vector": true }
{ "_id": true, "field1": false, "field2": false, "$vector": false }
The wildcard projection "*"
represents the whole of the document.
If you use this projection, it must be the only key in the projection.
If set to true ({ "*": true }
), all fields are returned.
If set to false ({ "*": false }
), no fields are returned, and each document is empty ({}
).
Projecting arrays and nested objects
For array fields, you can use a $slice
to specify which elements of the array to return.
Use one of the following formats:
// Return the first two elements
{ "arr": { "$slice": 2 } }
// Return the last two elements
{ "arr": { "$slice": -2 } }
// Skip 4 elements (from 0th index), return the next 2
{ "arr": { "$slice": [4, 2] } }
// Skip backward 4 elements (from the end), return next 2 elements (forward)
{ "arr": { "$slice": [-4, 2] } }
If a projection refers to a nested field, the keys in the subdocument are includes or excluded as requested. If you exclude all keys of an existing subdocument, then the document is returned with the subdocument present and an empty nested object.
Examples of nested document projections
Given the following document:
{
"_id": "z",
"a": {
"a1": 10,
"a2": 20
}
}
The results of various projections are as follows:
Projection | Result |
---|---|
|
|
|
|
|
|
|
|
|
|
Referencing overlapping paths or subpaths in a projection can create conflicting clauses and return an API error. For example, this projection is invalid:
// Invalid:
{ "a.a1": true, "a": true }
Projection examples by language
-
Python
-
TypeScript
-
Java
-
curl
For the Python client, the projection can be any of the following:
-
A dictionary (
Dict[str, Any]
) to include specific fields in the response, like{field_name: True}
. -
A dictionary (
Dict[str, Any]
) to exclude specific fields from the response, like{field_name: False}
. -
A list or other iterable over key names that are implied to be included in the projection.
The following two projections are equivalent:
document = collection.find_one(
{"_id": 101},
projection={"name": True, "city": True},
)
document = collection.find_one(
{"_id": 101},
projection=["name", "city"],
)
For information about default projections and handling for special fields, see the preceding explanation of projection clauses.
The TypeScript client takes in an untyped Plain Old JavaScript Object (POJO) for the projection
parameter.
The client also offers a StrictProjection<Schema>
type that provides full autocomplete and type checking for your document schema.
When specifying a projection, make sure that you handle the return type carefully. Consider type-casting.
import { StrictProjection } from '@datastax/astra-db-ts';
const doc = await collection.findOne({}, {
projection: {
'name': true,
'address.city': true,
},
});
interface MySchema {
name: string,
address: {
city: string,
state: string,
},
}
const doc = await collection.findOne({}, {
projection: {
'name': 1,
'address.city': 1,
// @ts-expect-error - `'address.car'` does not exist in type `StrictProjection<MySchema>`
'address.car': 0,
// @ts-expect-error - Type `{ $slice: number }` is not assignable to type `boolean | 0 | 1 | undefined`
'address.state': { $slice: 3 }
} satisfies StrictProjection<MySchema>,
});
For information about default projections and handling for special fields, see the preceding explanation of projection clauses.
To support the projection mechanism, the Java client has different Options
classes that provide the projection
method in the helpers.
This method takes an array of Projection
classes with the field name and a boolean flag indicating inclusion or exclusion.
Projection p1 = new Projection("field1", true);
Projection p2 = new Projection("field2", true);
FindOptions options1 = FindOptions.Builder.projection(p1, p2);
To simplify this syntax, you can use the Projections
syntactic sugar:
FindOptions options2 = FindOptions.Builder
.projection(Projections.include("field1", "field2"));
FindOptions options3 = FindOptions.Builder
.projection(Projections.exclude("field1", "field2"));
The Projection
class also provides a method to support $slice
for array fields:
// {"arr": {"$slice": 2}}
Projection sliceOnlyStart = Projections.slice("arr", 2, null);
// {"arr": {"$slice": [-4, 2]}}
Projection sliceOnlyRange =Projections.slice("arr", -4, 2);
// An you can use then freely in the different builders
FindOptions options4 = FindOptions.Builder
.projection(sliceOnlyStart);
For information about default projections and handling for special fields, see the preceding explanation of projection clauses.
In an HTTP request, include projection
as a find
parameter:
curl -sS -L -X POST "ASTRA_DB_API_ENDPOINT/api/json/v1/ASTRA_DB_KEYSPACE/ASTRA_DB_COLLECTION" \
--header "Token: ASTRA_DB_APPLICATION_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"find": {
"sort": { "$vector": [0.15, 0.1, 0.1, 0.35, 0.55] },
"projection": { "$vector": true, "name": true, "city": true }
"options": {
"includeSimilarity": true,
"includeSortVector": false,
"limit": 100
}
}
}' | jq
For information about default projections and handling for special fields, see the preceding explanation of projection clauses.