← Files FirebaseARCHIVED FILE

reference/data_seeding.md

5.79 KB · Sep 30, 2026 · 23:02 UTC

↓ Download file

# 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.

SHA-256: 70394a87d6c20a50517e4bd8fdabea740203d5645a79c70393a0a91abb628d0d