186 lines
5.8 KiB
Markdown
186 lines
5.8 KiB
Markdown
# Data Seeding & Bulk Operations Reference
|
|
|
|
Use this reference to populate local development databases for prototyping,
|
|
execute CI/CD tests, and perform bulk data migrations in production
|
|
environments.
|
|
|
|
______________________________________________________________________
|
|
|
|
## 1. Local Prototyping: Data Seeding
|
|
|
|
Local database seeding allows developer agents to test queries, mutations,
|
|
complex joins, and role-based access control (RBAC) under realistic conditions.
|
|
|
|
### The `seed_data.gql` Workflow
|
|
|
|
**Always write prototyping seed mutations to `dataconnect/seed_data.gql`**
|
|
(located at the project root, not inside `connector/`). This file is excluded
|
|
from production deployments and client SDK generation.
|
|
|
|
#### ⚠️ Seeding Directives Rule
|
|
|
|
**Do not declare `@auth` directives inside `seed_data.gql` mutations.** Since
|
|
this file runs locally to establish a test state and is not an exposed API
|
|
connector endpoint, authorization directives are completely unnecessary and
|
|
should be omitted.
|
|
|
|
### Seeding Independent Tables (FK Order)
|
|
|
|
When executing standard bulk insertions (`_insertMany`) across multiple tables,
|
|
**always insert parent tables before referencing them in child or join tables.**
|
|
|
|
```graphql
|
|
# dataconnect/seed_data.gql
|
|
mutation SeedIndependentTables @transaction {
|
|
# Step 1: Seed parent tables
|
|
movie_insertMany(data: [
|
|
{ id: "m-1", title: "Inception", genre: "sci-fi" },
|
|
{ id: "m-2", title: "The Matrix", genre: "action" }
|
|
])
|
|
|
|
actor_insertMany(data: [
|
|
{ id: "a-1", name: "Leonardo DiCaprio" },
|
|
{ id: "a-2", name: "Keanu Reeves" }
|
|
])
|
|
|
|
# Step 2: Seed join table (depends on pre-existing parent IDs)
|
|
movieActor_insertMany(data: [
|
|
{ movie: { id: "m-1" }, actor: { id: "a-1" }, role: "main" },
|
|
{ movie: { id: "m-2" }, actor: { id: "a-2" }, role: "main" }
|
|
])
|
|
}
|
|
```
|
|
|
|
### Seeding Related Tables (Nested Relational Inserts)
|
|
|
|
**To seed parent-child relationships atomically, perform a nested relational
|
|
insert using literal payloads.** This avoids the need to manage foreign keys
|
|
manually.
|
|
|
|
- **Omit Parent Foreign Keys**: **Do not specify the parent foreign key** (e.g.
|
|
`movieId`) inside the nested child objects. The database engine automatically
|
|
maps and resolves them.
|
|
|
|
```graphql
|
|
# dataconnect/seed_data.gql
|
|
mutation SeedMoviesAndReviews @transaction {
|
|
movie_insert(data: {
|
|
id: "m-1",
|
|
title: "Inception",
|
|
genre: "sci-fi",
|
|
# Nested reviews are inserted atomically without manual movieId mapping
|
|
reviews_on_movie: [
|
|
{
|
|
id: "r-1",
|
|
rating: 5,
|
|
reviewText: "Mind-bending masterpiece!",
|
|
user: { id: "user-123" } # Links to pre-existing user
|
|
},
|
|
{
|
|
id: "r-2",
|
|
rating: 4,
|
|
reviewText: "Visually stunning but complex.",
|
|
user: { id: "user-456" }
|
|
}
|
|
]
|
|
})
|
|
}
|
|
```
|
|
|
|
### Resetting Seed Data
|
|
|
|
For continuous testing or CI/CD flows, return the database to a zero state using
|
|
one of the following strategies:
|
|
|
|
- **Strategy A: Upsert Many (Idempotent)**: Re-run seeds using `_upsertMany`
|
|
mutations. This overrides existing records or inserts missing ones in a single
|
|
step.
|
|
- **Strategy B: Delete and Re-Insert**: Call `_deleteMany(all: true)` on your
|
|
tables in **reverse foreign key order** (child/join tables first, then parent
|
|
tables) followed by your seed `_insertMany` operations.
|
|
|
|
```graphql
|
|
# dataconnect/seed_data.gql
|
|
mutation ResetDatabaseToOriginalState @transaction {
|
|
# Delete child tables first to prevent FK constraint violations
|
|
movieActor_deleteMany(all: true)
|
|
actor_deleteMany(all: true)
|
|
movie_deleteMany(all: true)
|
|
# (Optional) Follow up with new _insertMany steps
|
|
}
|
|
```
|
|
|
|
______________________________________________________________________
|
|
|
|
## 2. Production: Admin SDK Bulk Operations
|
|
|
|
**Use the Firebase Admin SDK for Node.js for bulk data loading and production
|
|
migrations.** Avoid running large mutations directly via raw GraphQL endpoints
|
|
in production.
|
|
|
|
The Admin SDK provides direct, type-safe methods: `dc.insert`, `dc.insertMany`,
|
|
`dc.upsert`, and `dc.upsertMany`.
|
|
|
|
### SDK Bulk APIs Features:
|
|
|
|
- **No Manual GraphQL Strings**: Do not write raw `mutation {...}` strings when
|
|
executing privileged batch operations. Pass Javascript objects directly.
|
|
- **Relational Support**: The bulk helper methods natively support nested 1:Many
|
|
relationships inside the input arrays.
|
|
|
|
### SDK Bulk Operations Example
|
|
|
|
```typescript
|
|
import { initializeApp } from 'firebase-admin/app';
|
|
import { getDataConnect } from 'firebase-admin/data-connect';
|
|
|
|
const app = initializeApp();
|
|
const dc = getDataConnect({ location: "us-west2", serviceId: "my-service" });
|
|
|
|
const bulkMoviesData = [
|
|
{
|
|
id: "m-1",
|
|
title: "Inception",
|
|
genre: "sci-fi",
|
|
// Atomic nested relational inserts are fully supported
|
|
reviews_on_movie: [
|
|
{
|
|
rating: 5,
|
|
reviewText: "Incredible concept.",
|
|
user: { id: "user-123" }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
id: "m-2",
|
|
title: "The Matrix",
|
|
genre: "action",
|
|
reviews_on_movie: [
|
|
{
|
|
rating: 5,
|
|
reviewText: "A classic.",
|
|
user: { id: "user-456" }
|
|
}
|
|
]
|
|
}
|
|
];
|
|
|
|
// Atomically load thousands of records (parent and child tables combined)
|
|
const response = await dc.insertMany("movie", bulkMoviesData);
|
|
```
|
|
|
|
______________________________________________________________________
|
|
|
|
## 3. Production: Bulk Operations via raw SQL
|
|
|
|
When working with a stable schema in production, you can use standard SQL tools
|
|
(like `psql` or Cloud SQL import pipelines) to execute bulk data updates
|
|
directly on the PostgreSQL instance.
|
|
|
|
### 🚨 Critical SQL Operations Constraint
|
|
|
|
**Never modify your database schema directly using SQL tools.** Direct schema
|
|
alterations (`ALTER TABLE`, `CREATE INDEX`, etc.) outside of your `schema.gql`
|
|
file will bypass SQL Connect's schema compiler, breaking connector mappings, and
|
|
causing active client SDK integrations to fail.
|