播种数据并执行批量数据操作

在 Firebase SQL Connect 中,您可以根据工作流和环境,通过不同的方式执行批量数据加载和更新:

  • 在本地原型设计中,当您尝试替代架构时,可以使用 SQL Connect VS Code 扩展程序、SQL Connect 模拟器和本地数据库实例在本地开发环境中创建和调用数据播种变更。

  • 在生产开发中,如果架构稳定,当您执行较大的 CI/CD 流程并管理生产数据时,您有两种选择:

    • 首选方法是使用 Firebase Admin SDK,这是一组在特权环境中运行的库。

    • 您还可以将 SQL 工具与 Cloud SQL 实例搭配使用,以执行批量加载和更新,前提是您修改的是数据而不是数据库架构。直接使用 SQL 工具修改数据库架构可能会破坏 SQL Connect 架构和连接器。

本地原型设计:在本地实例中植入种子数据

在入门指南中,您设置了一个应用,以使用临时插入变更向单个表添加一条记录。

为了能够使用,影评应用需要电影、影评和用户的数据,以便对使用联接和其他操作的多表查询和变更进行原型设计,并使用真实数据。您可以扩展架构并为数据库添加种子数据。

原型设计环境需要代码来执行数据播种。本指南提供了一些示例,说明了以下内容:

  • 在各个表上使用 _insertMany 和 _upsertMany
  • 在相关表上使用 _insertMany

更新影评应用架构

您可以使用 _insertMany 和 _upsertMany 变更一次更新一个数据库表,也可以更新通过联接关系相关的多个表。下面显示了一个扩展的电影评价应用架构,有助于说明这些用例和示例。它将 schema.gql 扩展到起始 Movie 类型之外,以包含 Actor 和 MovieActor 类型,以便我们对更复杂的查询进行原型设计。

# Actors
# Suppose an actor can participate in multiple movies and movies can have multiple actors
# Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
  id: UUID!
  imageUrl: String! 
  name: String! @col(name: "name", dataType: "varchar(30)")
}

# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary key(s) of this table
# In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  # @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
  # In this case, @ref(fields: "movieId", references: "id") is implied
  movie: Movie!
  # movieId: UUID! <- this is created by the implied @ref
  actor: Actor!
  # actorId: UUID! <- this is created by the implied @ref
  role: String! # "main" or "supporting"
}

编写变更以植入初始状态数据

在原型设计期间,如果需要针对一系列离散值测试查询和变更,您可以使用多条记录填充数据。例如,您可能需要添加具有不同类型和评分的多个电影记录,以便进行测试比较和过滤。

将数据播种到 Movie 和 Actor 表中

根据原型设计阶段,您可以使用“入门指南”中介绍的相同方法插入一条或两条记录:即,您可以使用 SQL Connect VS Code 扩展程序中的 CodeLens 创建 _insert 变更、对数据进行硬编码,以及在 VS Code 中运行这些变更。

最终,使用 _insertMany 操作向表中添加多条记录会更合理。在影评应用示例中,这会在 Movie 和 Actor 中插入一组初始数据。

如需执行以下变更,请使用 SQL Connect VS Code 扩展程序,在相应的编辑器视图中,点击 Run (Production) 或 Run (Local) CodeLens 按钮,具体取决于您是使用生产服务还是本地数据库进行原型设计。

# insertMany for Movie
# 2 records shown
mutation {
  movie_insertMany(data: [
    {
      id: "550e8400-e29b-41d4-a716-446655440000",
      title: "Inception",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
      genre: "sci-fi",
    },
    {
      id: "550e8400-e29b-41d4-a716-446655440001",
      title: "The Matrix",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
      genre: "action",
    }
  ])
}
# insertMany for Actor
# 2 records shown
mutation {
  actor_insertMany(data: [
    {
      id: "123e4567-e89b-12d3-a456-426614174000",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdicaprio.jpeg?alt=media&token=452e030a-efa5-4ef4-bb81-502b23241316",
      name: "Leonardo DiCaprio"
    },
    {
      id: "123e4567-e89b-12d3-a456-426614174001",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fkeanu.jpg?alt=media&token=6056520c-ef3e-4823-aad0-108aab163115",
      name: "Keanu Reeves"
    }
   ])
}

将数据播种到 MovieActor 联接表

如需使用联接和其他复杂操作测试查询和变更,您可以向 MovieActor 表添加多条记录。

在这里,当您更新此类关系中的多个表时,可以添加 @transaction 指令,以确保更新正确完成。

mutation @transaction {
  movie_insertMany(data: [
    {
      id: "550e8400-e29b-41d4-a716-446655440000",
      title: "Inception",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
      genre: "sci-fi",
    },
    {
      id: "550e8400-e29b-41d4-a716-446655440001",
      title: "The Matrix",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
      genre: "action",
    }
  ])

  actor_insertMany(data: [
    {
      id: "123e4567-e89b-12d3-a456-426614174000",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fdicaprio.jpeg?alt=media&token=452e030a-efa5-4ef4-bb81-502b23241316",
      name: "Leonardo DiCaprio"
    },
    {
      id: "123e4567-e89b-12d3-a456-426614174001",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/actors%2Fkeanu.jpg?alt=media&token=6056520c-ef3e-4823-aad0-108aab163115",
      name: "Keanu Reeves"
    }
  ])
}

如需以原子方式为相关表播种,您可以使用字面量载荷执行嵌套关系插入。这样,您只需执行一次操作即可创建父记录及其关联的子记录,而无需手动关联外键。

对于一对多关系,您需要提供一个嵌套子记录数组。对于一对一关系,您需要提供单个嵌套子对象。

# Nested insert for Movie and Review (one-to-many)
# 1 movie and 2 reviews shown
mutation {
  movie_insert(data: {
    id: "550e8400-e29b-41d4-a716-446655440000",
    title: "Inception",
    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
    genre: "sci-fi",
    reviews_on_movie: [
      {
        id: "123e4567-e89b-12d3-a456-426614174002",
        rating: 5,
        reviewText: "Amazing concept!",
        user: { id: "user-uuid-123" }
      },
      {
        id: "123e4567-e89b-12d3-a456-426614174003",
        rating: 4,
        reviewText: "A bit confusing, but great.",
        user: { id: "user-uuid-456" }
      }
    ]
  })
}
# Nested insert for User and Profile (one-to-one)
mutation {
  user_insert(data: {
    id: "user-uuid-123",
    name: "Alice",
    profile_on_user: {
      bio: "Avid moviegoer and critic."
    }
  })
}

编写一个变更来重置种子数据

在原型设计和执行 CI/CD 期间,将数据重置为零状态以便对一组新数据执行一系列新测试可能很有用。

为此,如果您的原型代码未向表中添加记录,请使用 SQL Connect 提供的 _upsertMany 变更。

在以下示例中,系统会使用初始值调用 movie_upsertMany,以将电影记录更新为其原始状态。

mutation {
  # Execute an upsertMany operation to update the Movie table
  movie_upsertMany(data: [
    {
      id: "550e8400-e29b-41d4-a716-446655440000",
      title: "Inception",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
      genre: "sci-fi",
    },
    {
      id: "550e8400-e29b-41d4-a716-446655440001",
      title: "The Matrix",
      imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
      genre: "action",
    }
   …
}

生产开发:使用 Admin SDK 填充和更新

Firebase Admin SDK 适用于您希望在特权环境中工作的情况。当您想要加载数千条记录时,这是一个重要的用例,因为对生产数据进行批量数据操作至关重要。

安装 Firebase Admin SDK

即使您主要在本地工作,Firebase 也建议您设置 Admin SDK,以便您可以在特权环境(包括本地环境)中使用 Firebase SQL Connect。您需要为 Node.js 设置 Admin SDK。

您可以详细了解如何在其他 SQL Connect 用例中使用 Admin SDK。

执行生产数据的批量加载和更新

用于批量数据管理的 API 会代表您构建 GraphQL 变更,而不是要求您使用前面介绍的 executeGraphQL API 构建 mutation {...} 字符串,以便在本地添加几行数据。

管理 API 的一个主要优势是能够单独管理和重复使用 CI/CD 流程的数据数组,或为商品数据设置大型批量数据文件。

以下代码段演示了如何设置批量数据脚本。

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 data = [
  {
    id: "550e8400-e29b-41d4-a716-446655440000",
    title: "Inception",
    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Finception.jpg?alt=media&token=07b09781-b302-4623-a5c3-1956d0143168",
    genre: "sci-fi",
    // Nested reviews can be inserted atomically along with the movie
    reviews_on_movie: [
      {
        rating: 5,
        reviewText: "Amazing concept!",
        user: { id: "user-123" } // Link to existing user
      }
    ]
  },
  {
    id: "550e8400-e29b-41d4-a716-446655440001",
    title: "The Matrix",
    imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-quickstart-web.appspot.com/o/movies%2Fthe_matrix.jpg?alt=media&token=4975645d-fef8-409e-84a5-bcc1046e2059",
    genre: "action",
    reviews_on_movie: [
      {
        rating: 5,
        reviewText: "A masterpiece of sci-fi action.",
        user: { id: "user-456" }
      }
    ]
  }
];

// Methods of the bulk operations API
const resp = await dc.insert("movie" /*table name*/, data[0]);
// Or
const resp = await dc.insertMany("movie" /*table name*/, data);

// Or
const resp = await dc.upsert("movie" /*table name*/, data[0]);
// Or
const resp = await dc.upsertMany("movie" /*table name*/, data);

生产开发:使用 SQL 进行批量数据更新

如果您在生产环境中使用稳定的架构,并且不修改架构,则可以在 Cloud SQL 实例中管理数据加载和更新。

请参阅Cloud SQL for PostgreSQL 导入数据指南。

接下来怎么做?