メインコンテンツまでスキップ

Field projection

query から必要な field のみを返すことで、bandwidth を削減し performance を向上させます。​

多数の field を持つ document を query する場合、その data の一部だけが必要になることがよくあります。field projection がなければ、list view で name と email だけを表示する場合でも、application は document 全体を fetch します。field projection では、返す field を正確に指定することで bandwidth を削減し、performance を向上させます。projection は server で実行されるため、client-side で data を filter するのではなく、network transfer を削減できます。

Client code
// 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();

クイックスタート​

任意の query で、field name の array を指定して projectFields を呼び出します。

Client code
const results = await squid
.collection<User>('users')
.query()
.projectFields(['name', 'age'])
.dereference()
.snapshot();

// Results contain only the projected fields

field projection は、すべての query method で機能します。

Client code
const results = await squid
.collection<User>('users')
.query()
.where('status', '==', 'active')
.sortBy('name')
.limit(50)
.projectFields(['name', 'email', 'status'])
.dereference()
.snapshot();

コアコンセプト​

Document identifier は常に含まれる​

どの field を project するかにかかわらず、以下の identifier は常に result に含まれます。

  • __docId__: document の unique identifier。すべての database connector に存在します。projection に含めなくても、filter と sort に使用できます。
  • __id: document の primary key value。built-in database を使用する場合にのみ存在します。
Client code
// Filter by __docId__ without projecting it
const results = await squid
.collection<User>('users')
.query()
.where('__docId__', '>=', 'user_100')
.projectFields(['name', 'email'])
.dereference()
.snapshot();

composite primary key を持つ collection では、個々の key field も result の top level に含まれます。

Nested field​

dot notation を使用して nested field path を project します。

Client code
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

Error Handling​

注記

Document identifier field(__docId__ および __id)は、これらの rule の例外です。projection に含めなくても、常に filter と sort に使用できます。

Filter field は projection に含める必要がある​

projectFields を使用する場合、where clause で使用するすべての field を projection に含める必要があります。

Client code
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 field は projection に含める必要がある​

sortBy で使用する field は projection に含める必要があります。

Client code
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 の動作​

empty projection array の動作は database によって異なります。

  • Built-in database: document identifier のみを持つ record を返します。user data field は含まれません。
  • External database(MongoDB、PostgreSQL、MySQL など): error を throw します。少なくとも 1 つの field を指定する必要があります。
Client code
// 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 subscription​

field projection は real-time subscription で機能します。各 update には project された field のみが含まれます。

Client code
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));
});

ベストプラクティス​

  1. 大きな field または多数の field を持つ collection では特に、network transfer を最小化して query performance を向上させるため、必要な field のみを project します。

  2. validation error を避けるため、filter と sort で使用する field は常に projection に含めます。

    Client code
    // Correct: include 'status' since it's used in the filter
    const users = await squid
    .collection<User>('users')
    .query()
    .eq('status', 'active')
    .projectFields(['name', 'email', 'status'])
    .snapshot();
  3. 特定の property のみが必要な場合に nested object 全体を fetch しないよう、nested field には dot notation を使用します。

  4. source における bandwidth を削減するため、field の client-side filtering よりも field projection を優先します。

サポートされる database​

field projection はすべての Squid database connector でサポートされます。

  • Built-in database
  • MongoDB
  • PostgreSQL
  • MySQL
  • ClickHouse
  • MS SQL Server