304 lines
7.2 KiB
Markdown
304 lines
7.2 KiB
Markdown
# Advanced Features Reference
|
|
|
|
## Contents
|
|
- [Vector Similarity Search](#vector-similarity-search)
|
|
- [Full-Text Search](#full-text-search)
|
|
- [Cloud Functions Integration](#cloud-functions-integration)
|
|
- [Data Seeding & Bulk Operations](#data-seeding--bulk-operations)
|
|
|
|
---
|
|
|
|
## Vector Similarity Search
|
|
|
|
Semantic search using Vertex AI embeddings and PostgreSQL's `pgvector`.
|
|
|
|
### Schema Setup
|
|
|
|
```graphql
|
|
type Movie @table {
|
|
id: UUID! @default(expr: "uuidV4()")
|
|
title: String!
|
|
description: String
|
|
# Vector field for embeddings - size must match model output (768 for gecko)
|
|
descriptionEmbedding: Vector! @col(size: 768)
|
|
}
|
|
```
|
|
|
|
### Generate Embeddings in Mutations
|
|
|
|
Use `_embed` server value to auto-generate embeddings via Vertex AI:
|
|
|
|
```graphql
|
|
mutation CreateMovieWithEmbedding($title: String!, $description: String!)
|
|
@auth(level: USER) {
|
|
movie_insert(data: {
|
|
title: $title,
|
|
description: $description,
|
|
descriptionEmbedding_embed: {
|
|
model: "textembedding-gecko@003",
|
|
text: $description
|
|
}
|
|
})
|
|
}
|
|
```
|
|
|
|
### Similarity Search Query
|
|
|
|
Data Connect generates `_similarity` fields for Vector columns:
|
|
|
|
```graphql
|
|
query SearchMovies($query: String!) @auth(level: PUBLIC) {
|
|
movies_descriptionEmbedding_similarity(
|
|
compare_embed: { model: "textembedding-gecko@003", text: $query },
|
|
method: L2, # L2, COSINE, or INNER_PRODUCT
|
|
within: 2.0, # Max distance threshold
|
|
limit: 5
|
|
) {
|
|
id
|
|
title
|
|
description
|
|
_metadata { distance } # See how close each result is
|
|
}
|
|
}
|
|
```
|
|
|
|
### Similarity Parameters
|
|
|
|
| Parameter | Description |
|
|
|-----------|-------------|
|
|
| `compare` | Raw Vector to compare against |
|
|
| `compare_embed` | Generate embedding from text via Vertex AI |
|
|
| `method` | Distance function: `L2`, `COSINE`, `INNER_PRODUCT` |
|
|
| `within` | Max distance (results further are excluded) |
|
|
| `where` | Additional filters |
|
|
| `limit` | Max results to return |
|
|
|
|
### Custom Embeddings
|
|
|
|
Pass pre-computed vectors directly:
|
|
|
|
```graphql
|
|
mutation StoreCustomEmbedding($id: UUID!, $embedding: Vector!) @auth(level: USER) {
|
|
movie_update(id: $id, data: { descriptionEmbedding: $embedding })
|
|
}
|
|
|
|
query SearchWithCustomVector($vector: Vector!) @auth(level: PUBLIC) {
|
|
movies_descriptionEmbedding_similarity(
|
|
compare: $vector,
|
|
method: COSINE,
|
|
limit: 10
|
|
) { id title }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Full-Text Search
|
|
|
|
Fast keyword/phrase search using PostgreSQL's full-text capabilities.
|
|
|
|
### Enable with @searchable
|
|
|
|
```graphql
|
|
type Movie @table {
|
|
title: String! @searchable
|
|
description: String @searchable(language: "english")
|
|
genre: String @searchable
|
|
}
|
|
```
|
|
|
|
### Search Query
|
|
|
|
Data Connect generates `_search` fields:
|
|
|
|
```graphql
|
|
query SearchMovies($query: String!) @auth(level: PUBLIC) {
|
|
movies_search(
|
|
query: $query,
|
|
queryFormat: QUERY, # QUERY, PLAIN, PHRASE, or ADVANCED
|
|
limit: 20
|
|
) {
|
|
id title description
|
|
_metadata { relevance } # Relevance score
|
|
}
|
|
}
|
|
```
|
|
|
|
### Query Formats
|
|
|
|
| Format | Description |
|
|
|--------|-------------|
|
|
| `QUERY` | Web-style (default): quotes, AND, OR supported |
|
|
| `PLAIN` | Match all words, any order |
|
|
| `PHRASE` | Match exact phrase |
|
|
| `ADVANCED` | Full tsquery syntax |
|
|
|
|
### Tuning Results
|
|
|
|
```graphql
|
|
query SearchWithThreshold($query: String!) @auth(level: PUBLIC) {
|
|
movies_search(
|
|
query: $query,
|
|
relevanceThreshold: 0.05, # Min relevance score
|
|
where: { genre: { eq: "Action" }},
|
|
orderBy: [{ releaseYear: DESC }]
|
|
) { id title }
|
|
}
|
|
```
|
|
|
|
### Supported Languages
|
|
|
|
`english` (default), `french`, `german`, `spanish`, `italian`, `portuguese`, `dutch`, `danish`, `finnish`, `norwegian`, `swedish`, `russian`, `arabic`, `hindi`, `simple`
|
|
|
|
---
|
|
|
|
## Cloud Functions Integration
|
|
|
|
Trigger Cloud Functions when mutations execute.
|
|
|
|
### Basic Trigger (Node.js)
|
|
|
|
```typescript
|
|
import { onMutationExecuted } from "firebase-functions/dataconnect";
|
|
import { logger } from "firebase-functions";
|
|
|
|
export const onUserCreate = onMutationExecuted(
|
|
{
|
|
service: "myService",
|
|
connector: "default",
|
|
operation: "CreateUser",
|
|
region: "us-central1" // Must match Data Connect location
|
|
},
|
|
(event) => {
|
|
const variables = event.data.payload.variables;
|
|
const returnedData = event.data.payload.data;
|
|
|
|
logger.info("User created:", returnedData);
|
|
// Send welcome email, sync to analytics, etc.
|
|
}
|
|
);
|
|
```
|
|
|
|
### Basic Trigger (Python)
|
|
|
|
```python
|
|
from firebase_functions import dataconnect_fn, logger
|
|
|
|
@dataconnect_fn.on_mutation_executed(
|
|
service="myService",
|
|
connector="default",
|
|
operation="CreateUser"
|
|
)
|
|
def on_user_create(event: dataconnect_fn.Event):
|
|
variables = event.data.payload.variables
|
|
returned_data = event.data.payload.data
|
|
logger.info("User created:", returned_data)
|
|
```
|
|
|
|
### Event Data
|
|
|
|
```typescript
|
|
// event.authType: "app_user" | "unauthenticated" | "admin"
|
|
// event.authId: Firebase Auth UID (for app_user)
|
|
// event.data.payload.variables: mutation input variables
|
|
// event.data.payload.data: mutation response data
|
|
// event.data.payload.errors: any errors that occurred
|
|
```
|
|
|
|
### Filtering with Wildcards
|
|
|
|
```typescript
|
|
// Trigger on all User* mutations
|
|
export const onUserMutation = onMutationExecuted(
|
|
{ operation: "User*" },
|
|
(event) => { /* ... */ }
|
|
);
|
|
|
|
// Capture operation name
|
|
export const onAnyMutation = onMutationExecuted(
|
|
{ service: "myService", operation: "{operationName}" },
|
|
(event) => {
|
|
console.log("Operation:", event.params.operationName);
|
|
}
|
|
);
|
|
```
|
|
|
|
### Use Cases
|
|
|
|
- **Data sync**: Replicate to Firestore, BigQuery, external APIs
|
|
- **Notifications**: Send emails, push notifications on events
|
|
- **Async workflows**: Image processing, data aggregation
|
|
- **Audit logging**: Track all data changes
|
|
|
|
> ⚠️ **Avoid infinite loops**: Don't trigger mutations that would fire the same trigger. Use filters to exclude self-triggered events.
|
|
|
|
---
|
|
|
|
## Data Seeding & Bulk Operations
|
|
|
|
### Local Prototyping with _insertMany
|
|
|
|
```graphql
|
|
mutation SeedMovies @transaction {
|
|
movie_insertMany(data: [
|
|
{ id: "uuid-1", title: "Movie 1", genre: "Action" },
|
|
{ id: "uuid-2", title: "Movie 2", genre: "Drama" },
|
|
{ id: "uuid-3", title: "Movie 3", genre: "Comedy" }
|
|
])
|
|
}
|
|
```
|
|
|
|
### Reset Data with _upsertMany
|
|
|
|
```graphql
|
|
mutation ResetData {
|
|
movie_upsertMany(data: [
|
|
{ id: "uuid-1", title: "Movie 1", genre: "Action" },
|
|
{ id: "uuid-2", title: "Movie 2", genre: "Drama" }
|
|
])
|
|
}
|
|
```
|
|
|
|
### Clear All Data
|
|
|
|
```graphql
|
|
mutation ClearMovies {
|
|
movie_deleteMany(all: true)
|
|
}
|
|
```
|
|
|
|
### Production: Admin SDK Bulk Operations
|
|
|
|
```typescript
|
|
import { initializeApp } from 'firebase-admin/app';
|
|
import { getDataConnect } from 'firebase-admin/data-connect';
|
|
|
|
const app = initializeApp();
|
|
const dc = getDataConnect({ location: "us-central1", serviceId: "my-service" });
|
|
|
|
const movies = [
|
|
{ id: "uuid-1", title: "Movie 1", genre: "Action" },
|
|
{ id: "uuid-2", title: "Movie 2", genre: "Drama" }
|
|
];
|
|
|
|
// Bulk insert
|
|
await dc.insertMany("movie", movies);
|
|
|
|
// Bulk upsert
|
|
await dc.upsertMany("movie", movies);
|
|
|
|
// Single operations
|
|
await dc.insert("movie", movies[0]);
|
|
await dc.upsert("movie", movies[0]);
|
|
```
|
|
|
|
### Emulator Data Persistence
|
|
|
|
```bash
|
|
# Export emulator data
|
|
npx -y firebase-tools@latest emulators:export ./seed-data
|
|
|
|
# Start with saved data
|
|
npx -y firebase-tools@latest emulators:start --only dataconnect --import=./seed-data
|
|
```
|