你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 JavaScript 的 Azure Cosmos DB 客户端库 - 版本 4.2.0

/TypeScript

最新的 npm 锁屏提醒 生成状态

Azure Cosmos DB 是一种全球分布式多模型数据库服务,支持文档、键值、宽列和图形数据库。 此包适用于 JavaScript/TypeScript 应用程序,以便与 SQL API 数据库及其包含的 JSON 文档进行交互:

  • 创建 Cosmos DB 数据库并修改其设置
  • 创建和修改容器以存储 JSON 文档的集合
  • 在容器中创建、读取、更新和删除项(JSON 文档)
  • 使用类似于 SQL 的语法查询数据库中的文档

关键链接:

开始

先决条件

Azure 订阅和 Cosmos DB SQL API 帐户

必须具有 Azure 订阅,以及 Cosmos DB 帐户(SQL API)才能使用此包。

如果需要 Cosmos DB SQL API 帐户,可以使用 Azure Cloud Shell 使用此 Azure CLI 命令创建帐户:

az cosmosdb create --resource-group <resource-group-name> --name <cosmos-database-account-name>

也可以在 azure 门户 中创建帐户

NodeJS

此包通过 npm 分发,该 NodeJS 预安装了 LTS 版本。

CORS

如果需要为浏览器进行开发,则需要为 Cosmos DB 帐户设置 跨域资源共享(CORS) 规则。 按照链接文档中的说明为 Cosmos DB 创建新的 CORS 规则。

安装此包

npm install @azure/cosmos

获取帐户凭据

需要 Cosmos DB 帐户终结点密钥。 可以在 Azure 门户 中找到这些内容,也可以使用下面的 Azure CLI 代码片段。 代码片段的格式为 Bash shell。

az cosmosdb show --resource-group <your-resource-group> --name <your-account-name> --query documentEndpoint --output tsv
az cosmosdb keys list --resource-group <your-resource-group> --name <your-account-name> --query primaryMasterKey --output tsv

创建 CosmosClient 实例

与 Cosmos DB 的交互从 CosmosClient 类的实例开始

const { CosmosClient } = require("@azure/cosmos");

const endpoint = "https://your-account.documents.azure.com";
const key = "<database account masterkey>";
const client = new CosmosClient({ endpoint, key });

async function main() {
  // The rest of the README samples are designed to be pasted into this function body
}

main().catch((error) => {
  console.error(error);
});

为简单起见,我们直接将 keyendpoint 包含在代码中,但你可能希望从不使用源代码管理的项目(如 dotenv 或从环境变量加载)加载这些文件

在生产环境中,密钥等机密应存储在 Azure Key Vault

关键概念

初始化 CosmosClient后,即可与 Cosmos DB 中的主要资源类型进行交互:

  • 数据库:Cosmos DB 帐户可以包含多个数据库。 创建数据库时,指定与文档交互时要使用的 API:SQL、MongoDB、Gremlin、Cassandra 或 Azure 表。 使用 Database 对象管理其容器。

  • 容器:容器是 JSON 文档的集合。 通过使用 Container 对象上的方法,创建容器中的项(插入)、读取、更新和删除项。

  • :项是存储在容器中的 JSON 文档。 每个项都必须包含一个具有唯一标识容器内项的值的 id 键。 如果未提供 id,SDK 将自动生成一个。

有关这些资源的详细信息,请参阅 使用 Azure Cosmos 数据库、容器和项

例子

以下部分提供了几个代码片段,这些代码片段涵盖一些最常见的 Cosmos DB 任务,包括:

创建数据库

CosmosClient进行身份验证后,可以使用帐户中的任何资源。 下面的代码片段创建 NOSQL API 数据库。

const { database } = await client.databases.createIfNotExists({ id: "Test Database" });
console.log(database.id);

创建容器

此示例创建具有默认设置的容器

const { container } = await database.containers.createIfNotExists({ id: "Test Database" });
console.log(container.id);

使用分区键

此示例显示了支持的各种类型的分区键。

await container.item("id", "1").read();        // string type
await container.item("id", 2).read();          // number type
await container.item("id", true).read();       // boolean type
await container.item("id", {}).read();         // None type
await container.item("id", undefined).read();  // None type
await container.item("id", null).read();       // null type

如果分区键包含单个值,则可将其作为文本值或数组提供。

await container.item("id", "1").read();
await container.item("id", ["1"]).read();

如果分区键包含多个值,则应将其作为数组提供。

await container.item("id", ["a", "b"]).read();
await container.item("id", ["a", 2]).read();
await container.item("id", [{}, {}]).read();
await container.item("id", ["a", {}]).read();
await container.item("id", [2, null]).read();

插入项目

若要在容器中插入项,请将包含数据的对象传递给 Items.upsert。 Azure Cosmos DB 服务要求每个项都有一个 id 密钥。 如果未提供,SDK 将自动生成 id

本示例将多个项插入到容器中

const cities = [
  { id: "1", name: "Olympia", state: "WA", isCapitol: true },
  { id: "2", name: "Redmond", state: "WA", isCapitol: false },
  { id: "3", name: "Chicago", state: "IL", isCapitol: false }
];
for (const city of cities) {
  await container.items.create(city);
}

读取项

若要从容器中读取单个项,请使用 Item.read。 这比 id使用 SQL 查询的成本更低。

await container.item("1", "1").read();

容器上具有分层分区键的 CRUD

使用分层分区键创建容器

const containerDefinition = {
  id: "Test Database",
  partitionKey: {
    paths: ["/name", "/address/zip"],
    version: PartitionKeyDefinitionVersion.V2,
    kind: PartitionKeyKind.MultiHash,
  },
}
const { container } = await database.containers.createIfNotExists(containerDefinition);
console.log(container.id);

插入定义了分层分区键的项 - ["/name", "/address/zip"]

const item = {
  id: "1",
  name: 'foo',
  address: {
    zip: 100
  },
  active: true
}
await container.items.create(item);

若要从定义为分层分区键的容器读取单个项 - ["/name", "/address/zip"],

await container.item("1", ["foo", 100]).read();

使用定义的分层分区键查询具有分层分区键的项 - ["/name", "/address/zip"],

const { resources } = await container.items
  .query("SELECT * from c WHERE c.active = true", {
          partitionKey: ["foo", 100],
        })
  .fetchAll();
for (const item of resources) {
  console.log(`${item.name}, ${item.address.zip} `);
}

删除项

若要从容器中删除项,请使用 Item.delete

// Delete the first item returned by the query above
await container.item("1").delete();

查询数据库

Cosmos DB SQL API 数据库支持使用类似于 SQL 的语法通过 Items.query 查询容器中的项:

const { resources } = await container.items
  .query("SELECT * from c WHERE c.isCapitol = true")
  .fetchAll();
for (const city of resources) {
  console.log(`${city.name}, ${city.state} is a capitol `);
}

通过将包含参数及其值的对象传递给 items.query ,执行参数化查询:

const { resources } = await container.items
  .query({
    query: "SELECT * from c WHERE c.isCapitol = @isCapitol",
    parameters: [{ name: "@isCapitol", value: true }]
  })
  .fetchAll();
for (const city of resources) {
  console.log(`${city.name}, ${city.state} is a capitol `);
}

有关使用 SQL API 查询 Cosmos DB 数据库的详细信息,请参阅 使用 SQL 查询查询 Azure Cosmos DB 数据。

更改源拉取模型

可以为分区键、源范围或整个容器提取更改源。

若要处理更改源,请创建 ChangeFeedPullModelIterator实例。 最初创建 ChangeFeedPullModelIterator时,必须在 ChangeFeedIteratorOptions 内指定所需的 changeFeedStartFrom 值,该值包括读取更改的起始位置以及要提取更改的资源(分区键或 FeedRange)。 可以选择在 ChangeFeedIteratorOptions 中使用 maxItemCount 来设置每页接收的最大项目数。

注意:如果未指定任何 changeFeedStartFrom 值,则将从 Now()提取整个容器的更改源。

更改源有四个起始位置:

  • Beginning
// Signals the iterator to read changefeed from the beginning of time.
const options = {
  changeFeedStartFrom: ChangeFeedStartFrom.Beginning(),
};
const iterator = container.getChangeFeedIterator(options);
  • Time
// Signals the iterator to read changefeed from a particular point of time.
const time = new Date("2023/09/11"); // some sample date
const options = {
  changeFeedStartFrom: ChangeFeedStartFrom.Time(time),
};
  • Now
// Signals the iterator to read changefeed from this moment onward.
const options = {
  changeFeedStartFrom: ChangeFeedStartFrom.Now(),
};
  • Continuation
// Signals the iterator to read changefeed from a saved point.
const continuationToken = "some continuation token recieved from previous request";
const options = {
  changeFeedStartFrom: ChangeFeedStartFrom.Continuation(continuationToken),
};

下面是为分区键提取更改源的示例

const partitionKey = "some-partition-Key-value";
const options = {
  changeFeedStartFrom: ChangeFeedStartFrom.Beginning(partitionKey),
};

const iterator = container.items.getChangeFeedIterator(options);

while (iterator.hasMoreResults) {
  const response = await iterator.readNext();
  // process this response
}

由于更改源实际上是包含所有未来写入和更新的项的无限列表,因此 hasMoreResults 的值始终 true。 尝试读取更改源并且没有可用的新更改时,会收到一个具有 NotModified 状态的响应。

可在此处 找到更详细的更改源用法指南和示例。

错误处理

SDK 生成在操作期间可能发生的各种错误。

  1. 如果操作的响应返回错误代码 >=400,则会引发 ErrorResponse
  2. 如果中止因超时在内部调用,则会引发 TimeoutError
  3. 如果任何用户通过信号导致中止,则会引发 AbortError
  4. 如果基础系统调用因网络问题而失败,将引发 RestError
  5. 任何 devDependencies 生成的错误。 例如 @azure/identity 包可能会引发 CredentialUnavailableError

下面是一个示例,用于处理类型为 ErrorResponseTimeoutErrorAbortErrorRestError的错误。

try {
  // some code
} catch (err) {
  if (err instanceof ErrorResponse) {
    // some specific error handling.
  } else if (err instanceof RestError) {
    // some specific error handling.
  }
  // handle other type of errors in similar way.
  else {
    // for any other error.
  }
}

请务必正确处理这些错误,以确保应用程序能够正常地从任何故障中恢复,并继续按预期运行。 有关其中一些错误的更多详细信息及其可能的解决方案,请参阅此处

故障 排除

常规

与服务返回的 Cosmos DB 错误交互时,对应于为 REST API 请求返回的相同 HTTP 状态代码:

Azure Cosmos DB 的 HTTP 状态代码

冲突

例如,如果尝试使用已在 Cosmos DB 数据库中使用的 id 创建项,则返回 409 错误,指示冲突。 在以下代码片段中,通过捕获异常并显示有关错误的其他信息来正常处理错误。

try {
  await containers.items.create({ id: "existing-item-id" });
} catch (error) {
  if (error.code === 409) {
    console.log("There was a conflict with an existing item");
  }
}

转译

Azure SDK 旨在支持 ES5 JavaScript 语法和 LTS 版本的 Node.js。 如果需要对早期 JavaScript 运行时(如 Internet Explorer 或 Node 6)的支持,则需要在生成过程中传输 SDK 代码。

使用重试处理暂时性错误

使用 Cosmos DB 时,可能会遇到由服务强制实施 速率 限制或网络中断等其他暂时性问题导致的暂时性故障。 有关处理此类故障的信息,请参阅云设计模式指南中的 重试模式,以及相关的 断路器模式

伐木

启用日志记录可能有助于发现有关故障的有用信息。 若要查看 HTTP 请求和响应的日志,请将 AZURE_LOG_LEVEL 环境变量设置为 info。 或者,可以通过在 @azure/logger中调用 setLogLevel 在运行时启用日志记录。 在使用 AZURE_LOG_LEVEL 时,请确保在初始化日志记录库之前对其进行设置。 理想情况下,如果使用 dotenv 等库,请确保在记录库之前初始化此类库。

const { setLogLevel } = require("@azure/logger");
setLogLevel("info");

有关如何启用日志的更详细说明,可以查看 @azure/记录器包文档

诊断

Cosmos 诊断功能提供对所有客户端操作的增强见解。 向响应所有客户端操作添加 CosmosDiagnostics 对象。 如

  • 点查找操作响应 - item.read()container.create()database.delete()
  • 查询操作响应 -queryIterator.fetchAll()
  • 批量和批处理操作 -item.batch()
  • 错误/异常响应对象。

向响应所有客户端操作添加 CosmosDiagnostics 对象。 有 3 个 Cosmos 诊断级别、信息、调试和调试不安全。 如果只有信息用于生产系统,而调试和调试不安全则用于开发和调试,因为它们消耗的资源要高得多。 可以通过 2 种方式设置 Cosmos 诊断级别

  • 以编程方式
  const client = new CosmosClient({ endpoint, key, diagnosticLevel: CosmosDbDiagnosticLevel.debug });
  • 使用环境变量。 (环境变量设置的诊断级别优先于通过客户端选项设置它。
  export AZURE_COSMOSDB_DIAGNOSTICS_LEVEL="debug"

Cosmos 诊断有三个成员

  • ClientSideRequestStatistics 类型:包含聚合诊断详细信息,包括元数据查找、重试、联系的终结点,以及有效负载大小和持续时间等请求和响应统计信息。 (始终收集,可用于生产系统。

  • DiagnosticNode:是一种类似树的结构,用于捕获详细的诊断信息。 类似于浏览器中存在的 har 录制。 此功能默认处于禁用状态,仅用于调试非生产环境。 (在诊断级别调试和调试不安全收集)

  • ClientConfig:捕获客户端初始化期间与客户端配置设置相关的基本信息。 (在诊断级别调试和调试不安全收集)

请确保永远不会在生产环境中将诊断级别设置为 debug-unsafe,因为此级别 CosmosDiagnostics 捕获请求和响应有效负载;如果选择记录它(默认情况下,@azure/logger 记录在 verbose 级别)。 这些有效负载可能会在日志接收器中捕获。

使用诊断

  • 由于 diagnostics 已添加到所有 Response 对象。 可以按如下所示以编程方式访问 CosmosDiagnostic
  // For point look up operations
  const { container, diagnostics: containerCreateDiagnostic } =
    await database.containers.createIfNotExists({
      id: containerId,
      partitionKey: {
        paths: ["/key1"],
      },
  });

  // For Batch operations
   const operations: OperationInput[] = [
    {
      operationType: BulkOperationType.Create,
      resourceBody: { id: 'A', key: "A", school: "high" },
    },
  ];
  const response = await container.items.batch(operations, "A"); 
  
  // For query operations
  const queryIterator = container.items.query("select * from c");
  const { resources, diagnostics } = await queryIterator.fetchAll();

  // While error handling
  try {
    // Some operation that might fail
  } catch (err) {
    const diagnostics = err.diagnostics
  }
  • 还可以使用 @azure/logger记录 diagnostics,始终使用 verbose 级别的 @azure/logger 记录诊断。 因此,如果将诊断级别设置为 debugdebug-unsafe 并将 @azure/logger 级别设置为 verbose,则会记录 diagnostics

后续步骤

更多示例代码

SDK 的 GitHub 存储库中提供了多个示例。 这些示例为使用 Cosmos DB 时经常遇到的其他方案提供示例代码:

  • 数据库操作
  • 容器操作
  • 项操作
  • 配置索引
  • 读取容器更改源
  • 存储过程
  • 更改数据库/容器吞吐量设置
  • 多区域写入操作

局限性

目前,以下功能 不支持。 有关替代选项,请查看下面的 解决方法 部分。

数据平面限制:

  • 使用 DISTINCT 子查询中的 COUNT 的查询
  • 直接 TCP 模式访问
  • 聚合跨分区查询(如排序、计数和非重复查询)不支持继续标记。 可流式处理查询,如 SELECT * FROM WHERE,支持延续标记。 请参阅“解决方法”部分,了解如何在没有继续标记的情况下执行不可流式传输的查询。
  • 更改源:处理器
  • 更改源:读取多个分区键值
  • 更改源拉取模型对部分分层分区键的支持 #27059
  • 混合类型的跨分区 ORDER BY
  • 控制平面限制:

    • 获取 CollectionSizeUsage、DatabaseUsage 和 DocumentUsage 指标
    • 创建地理空间索引
    • 更新自动缩放吞吐量

    解决方法

    跨分区查询的延续标记

    可以使用 侧车模式实现具有延续令牌支持的跨分区查询。 此模式还可以使应用程序由异类组件和技术组成。

    执行不可构造的跨分区查询

    若要在不使用延续标记的情况下执行不可流式传输的查询,可以使用所需的查询规范和选项创建查询迭代器。 以下示例代码演示如何使用查询迭代器提取所有结果,而无需继续标记:

    const querySpec = {
      query: "SELECT c.status, COUNT(c.id) AS count FROM c GROUP BY c.status",
    };
    const queryOptions = {
      maxItemCount: 10, // maximum number of items to return per page
      enableCrossPartitionQuery: true,
    };
    const querIterator = await container.items.query(querySpec, queryOptions);
    while (querIterator.hasMoreResults()) {
      const { resources: result } = await querIterator.fetchNext();
      //Do something with result
    }
    

    此方法还可用于可流式处理查询。

    控制平面操作

    通常,可以使用 Azure 门户Azure Cosmos DB 资源提供程序 REST APIAzure CLIPowerShell 来控制平面不受支持的限制。

    其他文档

    有关 Cosmos DB 服务的详细信息,请参阅有关 docs.microsoft.com Azure Cosmos DB 文档

    贡献

    若要参与此库,请阅读 贡献指南 了解有关如何生成和测试代码的详细信息。

    印象