Field projection
Reduce bandwidth and improve performance by returning only the fields you need from queries.
When querying documents with many fields, you often only need a subset of that data. Without field projection, your application fetches entire documents even when displaying just a name and email in a list view. Field projection reduces bandwidth and improves performance by letting you specify exactly which fields to return. Projection happens on the server, so you're reducing network transfer rather than filtering data client-side.
// Without projection: fetches all 20+ fields
const users = await squid.collection<User>('users').query().snapshot();
// With projection: fetches only what you need
const users = await squid.collection<User>('users').query().projectFields(['name', 'email']).snapshot();
Quick start
Call projectFields on any query with an array of field names:
const results = await squid.collection<User>('users').query().projectFields(['name', 'age']).dereference().snapshot();
// Results contain only the projected fields
Field projection works with all query methods:
const results = await squid.collection<User>('users').query().where('status', '==', 'active').sortBy('name').limit(50).projectFields(['name', 'email', 'status']).dereference().snapshot();
Core concepts
Document identifiers are always included
Regardless of which fields you project, the following identifiers are always included in results:
__docId__: The document's unique identifier, present on all database integrations. You can use it for filtering and sorting even without including it in your projection.__id: The document's primary key value, present only when using the built-in database.
// Filter by __docId__ without projecting it
const results = await squid.collection<User>('users').query().where('__docId__', '>=', 'user_100').projectFields(['name', 'email']).dereference().snapshot();
For collections with composite primary keys, the individual key fields are also included at the top level of results.
Nested fields
Use dot notation to project nested field paths:
interface User {
name: string;
address: {
city: string;
zip: string;
country: string;
};
}
const results = await squid.collection<User>('users').query().projectFields(['name', 'address.city']).dereference().snapshot();
// Result: { name: 'Alice', address: { city: 'NYC' } }
// Note: address.zip and address.country are NOT included
Validation rules
Document identifier fields (__docId__ and __id) are exceptions to these rules - they can always be used for filtering and sorting without being included in your projection.
Filter fields must be in projection
When using projectFields, any field used in a where clause must be included in the projection:
const usersCollection = squid.collection<User>('users');
// Error: Cannot filter by 'email' that is not included in projectFields
usersCollection.query().where('email', '==', 'test@example.com').projectFields(['name', 'age']);
// Correct: Include email in projection
usersCollection.query().where('email', '==', 'test@example.com').projectFields(['name', 'age', 'email']);
Sort fields must be in projection
Fields used in sortBy must be included in the projection:
const usersCollection = squid.collection<User>('users');
// Error: Cannot sort by 'email' that is not included in projectFields
usersCollection.query().sortBy('email').projectFields(['name', 'age']);
// Correct: Include email in projection
usersCollection.query().sortBy('email').projectFields(['name', 'age', 'email']);
Empty array behavior
Empty projection arrays behave differently depending on the database:
- Built-in database: Returns records with only document identifiers, no user data fields.
- External databases (MongoDB, PostgreSQL, MySQL, etc.): Throws an error. You must specify at least one field.
// For built-in database: returns records with only identifiers
const results = await squid.collection<User>('users').query().projectFields([]).snapshot();
// For external databases: throws error
const mongoCollection = squid.collection<User>('users', 'mongoConnectorId');
mongoCollection.query().projectFields([]); // Error!
Real-time subscriptions
Field projection works with real-time subscriptions. Each update contains only the projected fields:
squid
.collection<User>('users')
.query()
.projectFields(['name', 'age'])
.snapshots()
.subscribe((refs) => {
// Each update contains only name and age
console.log(refs.map((ref) => ref.data));
});
Supported databases
Field projection is supported on all Squid database connectors:
- Built-in database
- MongoDB
- PostgreSQL
- MySQL
- ClickHouse
- MS SQL Server