适用于 Azure Functions 2.x 及更高版本的 Azure Cosmos DB 输出绑定

Azure Cosmos DB 输出绑定允许使用 SQL API 将新文档写入 Azure Cosmos DB 数据库。

有关设置和配置详细信息,请参阅概述

示例

除非另有说明,否则本文中的示例针对的都是 Azure Cosmos DB 扩展的版本 3.x。 若要与扩展版本 4.x 配合使用,需要将 collection 属性和属性名称中的字符串替换为 container

本部分包含以下示例:

这些示例引用简单的 ToDoItem 类型:

namespace CosmosDBSamplesV2
{
    public class ToDoItem
    {
        public string id { get; set; }
        public string Description { get; set; }
    }
}

队列触发器,写入一个文档

以下示例演示一个使用队列存储消息中提供的数据,将文档添加到数据库的 C# 函数

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using System;

namespace CosmosDBSamplesV2
{
    public static class WriteOneDoc
    {
        [FunctionName("WriteOneDoc")]
        public static void Run(
            [QueueTrigger("todoqueueforwrite")] string queueMessage,
            [CosmosDB(
                databaseName: "ToDoItems",
                collectionName: "Items",
                ConnectionStringSetting = "CosmosDBConnection")]out dynamic document,
            ILogger log)
        {
            document = new { Description = queueMessage, id = Guid.NewGuid() };

            log.LogInformation($"C# Queue trigger function inserted one row");
            log.LogInformation($"Description={queueMessage}");
        }
    }
}

队列触发器,写入一个文档(v4 扩展)

使用 Cosmos DB 扩展版本 4.x 或更高版本的应用将具有不同的特性属性,如下所示。 以下示例演示一个使用队列存储消息中提供的数据,将文档添加到数据库的 C# 函数

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using System;

namespace CosmosDBSamplesV2
{
    public static class WriteOneDoc
    {
        [FunctionName("WriteOneDoc")]
        public static void Run(
            [QueueTrigger("todoqueueforwrite")] string queueMessage,
            [CosmosDB(
                databaseName: "ToDoItems",
                containerName: "Items",
                Connection = "CosmosDBConnection")]out dynamic document,
            ILogger log)
        {
            document = new { Description = queueMessage, id = Guid.NewGuid() };

            log.LogInformation($"C# Queue trigger function inserted one row");
            log.LogInformation($"Description={queueMessage}");
        }
    }
}

队列触发器,使用 IAsyncCollector 来写入文档

以下示例演示了一个 C# 函数,该函数使用以队列消息 JSON 格式提供的数据将文档集添加到数据库。

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace CosmosDBSamplesV2
{
    public static class WriteDocsIAsyncCollector
    {
        [FunctionName("WriteDocsIAsyncCollector")]
        public static async Task Run(
            [QueueTrigger("todoqueueforwritemulti")] ToDoItem[] toDoItemsIn,
            [CosmosDB(
                databaseName: "ToDoItems",
                collectionName: "Items",
                ConnectionStringSetting = "CosmosDBConnection")]
                IAsyncCollector<ToDoItem> toDoItemsOut,
            ILogger log)
        {
            log.LogInformation($"C# Queue trigger function processed {toDoItemsIn?.Length} items");

            foreach (ToDoItem toDoItem in toDoItemsIn)
            {
                log.LogInformation($"Description={toDoItem.Description}");
                await toDoItemsOut.AddAsync(toDoItem);
            }
        }
    }
}

可以使用以下 C# 模式之一创建 C# 函数:

  • 进程内类库:编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。
  • 独立进程类库:编译的 C# 函数,该函数在独立于运行时的进程中运行。 支持在 .NET 5.0 上运行的 C# 函数需要独立的进程。
  • C# 脚本:主要在 Azure 门户中创建 C# 函数时使用。

队列触发器,通过返回值将消息保存到数据库

以下示例展示了一个 Java 函数,它向数据库中添加一个文档,该文档包含来自队列存储中消息的数据。

@FunctionName("getItem")
@CosmosDBOutput(name = "database",
  databaseName = "ToDoList",
  collectionName = "Items",
  connectionStringSetting = "AzureCosmosDBConnection")
public String cosmosDbQueryById(
    @QueueTrigger(name = "msg",
      queueName = "myqueue-items",
      connection = "AzureWebJobsStorage")
    String message,
    final ExecutionContext context)  {
     return "{ id: \"" + System.currentTimeMillis() + "\", Description: " + message + " }";
   }

HTTP 触发器,通过返回值将文件保存到数据库

以下示例显示了 Java 函数,其签名使用 @CosmosDBOutput 注释,并且返回值类型为 String。 该函数返回的 JSON 文档将自动写入相应的 CosmosDB 集合。

    @FunctionName("WriteOneDoc")
    @CosmosDBOutput(name = "database",
      databaseName = "ToDoList",
      collectionName = "Items",
      connectionStringSetting = "Cosmos_DB_Connection_String")
    public String run(
            @HttpTrigger(name = "req",
              methods = {HttpMethod.GET, HttpMethod.POST},
              authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {

        // Item list
        context.getLogger().info("Parameters are: " + request.getQueryParameters());

        // Parse query parameter
        String query = request.getQueryParameters().get("desc");
        String name = request.getBody().orElse(query);

        // Generate random ID
        final int id = Math.abs(new Random().nextInt());

        // Generate document
        final String jsonDocument = "{\"id\":\"" + id + "\", " +
                                    "\"description\": \"" + name + "\"}";

        context.getLogger().info("Document to be saved: " + jsonDocument);

        return jsonDocument;
    }

HTTP 触发器,通过 OutputBinding 将一个文档保存到数据库

以下示例显示了 Java 函数,该函数通过 OutputBinding<T> 输出参数将文档写入 CosmosDB。 在此示例中,需要使用 @CosmosDBOutputoutputItem 参数提供注释,而不要使用函数签名。 使用 OutputBinding<T>,让函数可以利用绑定将文档写入 CosmosDB,同时还可向函数调用者返回不同的值,例如 JSON 或 XML 文档。

    @FunctionName("WriteOneDocOutputBinding")
    public HttpResponseMessage run(
            @HttpTrigger(name = "req",
              methods = {HttpMethod.GET, HttpMethod.POST},
              authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> request,
            @CosmosDBOutput(name = "database",
              databaseName = "ToDoList",
              collectionName = "Items",
              connectionStringSetting = "Cosmos_DB_Connection_String")
            OutputBinding<String> outputItem,
            final ExecutionContext context) {

        // Parse query parameter
        String query = request.getQueryParameters().get("desc");
        String name = request.getBody().orElse(query);

        // Item list
        context.getLogger().info("Parameters are: " + request.getQueryParameters());

        // Generate random ID
        final int id = Math.abs(new Random().nextInt());

        // Generate document
        final String jsonDocument = "{\"id\":\"" + id + "\", " +
                                    "\"description\": \"" + name + "\"}";

        context.getLogger().info("Document to be saved: " + jsonDocument);

        // Set outputItem's value to the JSON document to be saved
        outputItem.setValue(jsonDocument);

        // return a different document to the browser or calling client.
        return request.createResponseBuilder(HttpStatus.OK)
                      .body("Document created successfully.")
                      .build();
    }

HTTP 触发器,通过 OutputBinding 将多个文档保存到数据库

以下示例显示了 Java 函数,该函数通过 OutputBinding<T> 输出参数将多个文档写入 CosmosDB。 在此示例中,需使用 @CosmosDBOutputoutputItem 参数提供注释,而不要使用函数签名。 输出参数 outputItem 有一个 ToDoItem 对象列表作为其模板参数类型。 使用 OutputBinding<T>,让函数可以利用绑定将文档写入 CosmosDB,同时还可向函数调用者返回不同的值,例如 JSON 或 XML 文档。

    @FunctionName("WriteMultipleDocsOutputBinding")
    public HttpResponseMessage run(
            @HttpTrigger(name = "req",
              methods = {HttpMethod.GET, HttpMethod.POST},
              authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> request,
            @CosmosDBOutput(name = "database",
              databaseName = "ToDoList",
              collectionName = "Items",
              connectionStringSetting = "Cosmos_DB_Connection_String")
            OutputBinding<List<ToDoItem>> outputItem,
            final ExecutionContext context) {

        // Parse query parameter
        String query = request.getQueryParameters().get("desc");
        String name = request.getBody().orElse(query);

        // Item list
        context.getLogger().info("Parameters are: " + request.getQueryParameters());

        // Generate documents
        List<ToDoItem> items = new ArrayList<>();

        for (int i = 0; i < 5; i ++) {
          // Generate random ID
          final int id = Math.abs(new Random().nextInt());

          // Create ToDoItem
          ToDoItem item = new ToDoItem(String.valueOf(id), name);

          items.add(item);
        }

        // Set outputItem's value to the list of POJOs to be saved
        outputItem.setValue(items);
        context.getLogger().info("Document to be saved: " + items);

        // return a different document to the browser or calling client.
        return request.createResponseBuilder(HttpStatus.OK)
                      .body("Documents created successfully.")
                      .build();
    }

Java 函数运行时库中,对其值将写入到 Cosmos DB 的参数使用 @CosmosDBOutput 注释。 注释参数类型应当为 OutputBinding<T>,其中 T 是本机 Java 类型或 POJO。

以下示例演示 function.json 文件中的一个 Azure Cosmos DB 输出绑定以及使用该绑定的 JavaScript 函数。 该函数使用一个用于某个队列的队列输入绑定,该队列以下列格式接收 JSON:

{
    "name": "John Henry",
    "employeeId": "123456",
    "address": "A town nearby"
}

该函数按下列格式为每个记录创建 Azure Cosmos DB 文档:

{
    "id": "John Henry-123456",
    "name": "John Henry",
    "employeeId": "123456",
    "address": "A town nearby"
}

下面是 function.json 文件中的绑定数据:

{
    "name": "employeeDocument",
    "type": "cosmosDB",
    "databaseName": "MyDatabase",
    "collectionName": "MyCollection",
    "createIfNotExists": true,
    "connectionStringSetting": "MyAccount_COSMOSDB",
    "direction": "out"
}

配置部分解释了这些属性。

JavaScript 代码如下所示:

    module.exports = async function (context) {

      context.bindings.employeeDocument = JSON.stringify({
        id: context.bindings.myQueueItem.name + "-" + context.bindings.myQueueItem.employeeId,
        name: context.bindings.myQueueItem.name,
        employeeId: context.bindings.myQueueItem.employeeId,
        address: context.bindings.myQueueItem.address
      });
    };

对于批量插入,请先构建对象,然后运行 stringify 函数。 JavaScript 代码如下所示:

    module.exports = async function (context) {

        context.bindings.employeeDocument = JSON.stringify([
        {
            "id": "John Henry-123456",
            "name": "John Henry",
            "employeeId": "123456",
            "address": "A town nearby"
        },
        {
            "id": "John Doe-123457",
            "name": "John Doe",
            "employeeId": "123457",
            "address": "A town far away"
        }]);
    };

下面的示例演示如何使用输出绑定将数据写入 Cosmos DB。 绑定在函数的配置文件 (functions.json) 中声明,并从队列消息中获取数据,然后写出到 Cosmos DB 文档中。

{ 
  "name": "EmployeeDocument",
  "type": "cosmosDB",
  "databaseName": "MyDatabase",
  "collectionName": "MyCollection",
  "createIfNotExists": true,
  "connectionStringSetting": "MyStorageConnectionAppSetting",
  "direction": "out" 
} 

在 run.ps1 文件中,从函数返回的对象将映射到 EmployeeDocument 对象,该对象将持久保存在数据库中。

param($QueueItem, $TriggerMetadata) 

Push-OutputBinding -Name EmployeeDocument -Value @{ 
    id = $QueueItem.name + '-' + $QueueItem.employeeId 
    name = $QueueItem.name 
    employeeId = $QueueItem.employeeId 
    address = $QueueItem.address 
} 

下面的示例演示如何将文档作为函数的输出写入 Azure Cosmos DB 数据库。

绑定定义在 function.json 中定义,其中 type 设置为 cosmosDB

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "cosmosDB",
      "direction": "out",
      "name": "doc",
      "databaseName": "demodb",
      "collectionName": "data",
      "createIfNotExists": "true",
      "connectionStringSetting": "AzureCosmosDBConnectionString"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

若要写入数据库,请将文档对象传递给数据库参数的 set 方法。

import azure.functions as func

def main(req: func.HttpRequest, doc: func.Out[func.Document]) -> func.HttpResponse:

    request_body = req.get_body()

    doc.set(func.Document.from_json(request_body))

    return 'OK'

特性

进程内独立进程 C# 库使用特性来定义函数。 C# 脚本改为使用 function.json 配置文件。

Attribute 属性 说明
ConnectionStringSetting 应用设置或设置集合的名称,用于指定如何连接到受监视的 Azure Cosmos DB 帐户。 有关详细信息,请参阅连接
DatabaseName 带有受监视的集合的 Azure Cosmos DB 数据库的名称。
CollectionName 受监视的集合的名称。
CreateIfNotExists 一个用于指示是否创建集合(如果不存在)的布尔值。 默认值为 false,因为新集合是使用保留的吞吐量创建的,具有成本方面的隐含意义。 有关详细信息,请参阅定价页
PartitionKey CreateIfNotExists 为 true 时,将定义所创建集合的分区键路径。 可以包含绑定参数。
* CollectionThroughput CreateIfNotExists 为 true 时,将定义所创建集合的吞吐量
PreferredLocations (可选)为 Azure Cosmos DB 服务中的异地复制数据库帐户定义首选位置(区域)。 值应以逗号分隔。 例如,China North,China North,China North
UseMultipleWriteLocations (可选)在与 PreferredLocations 一起设置为 true 时,支持 Azure Cosmos DB 服务中的多区域写入

批注

Java 函数运行时库中,对写入 Azure Cosmos DB 的参数使用 @CosmosDBOutput 注释。 此注释支持以下属性:

配置

下表解释了在 function.json 文件中设置的绑定配置属性,其中属性因扩展版本而异。

function.json 属性 说明
connectionStringSetting 应用设置或设置集合的名称,用于指定如何连接到受监视的 Azure Cosmos DB 帐户。 有关详细信息,请参阅连接
databaseName 带有受监视的集合的 Azure Cosmos DB 数据库的名称。
collectionName 受监视的集合的名称。
createIfNotExists 一个用于指示是否创建集合(如果不存在)的布尔值。 默认值为 false,因为新集合是使用保留的吞吐量创建的,具有成本方面的隐含意义。 有关详细信息,请参阅定价页
partitionKey createIfNotExists 为 true 时,将定义所创建集合的分区键路径。 可以包含绑定参数。
* collectionThroughput createIfNotExists 为 true 时,将定义所创建集合的吞吐量
preferredLocations (可选)为 Azure Cosmos DB 服务中的异地复制数据库帐户定义首选位置(区域)。 值应以逗号分隔。 例如,China North,China North,China North
useMultipleWriteLocations (可选)在与 preferredLocations 一起设置为 true 时,支持 Azure Cosmos DB 服务中的多区域写入

有关完整示例的信息,请参阅示例部分

使用情况

默认情况下,当写入函数中的输出参数时,将在数据库中创建一个文档。 本文档将自动生成的 GUID 作为文档 ID。 可以通过在传递给输出参数的 JSON 对象中指定 id 属性来指定输出文档的文档 ID。

注意

如果指定现有文档的 ID,它会被新的输出文档覆盖。

连接

connectionStringSetting/connectionleaseConnectionStringSetting/leaseConnection 属性是对指定应用应该如何连接到 Azure Cosmos DB 的环境配置的引用。 这些属性可以指定:

如果配置的值既是单个设置的完全匹配,也是其他设置的前缀匹配,则使用完全匹配。

连接字符串

数据库帐户的连接字符串应存储在应用程序设置中,其名称与绑定配置的 connection 属性指定的值匹配。

基于标识的连接

如果使用 4.x 或更高版本的扩展,则无需将连接字符串与机密一起使用,可以使应用使用 Azure Active Directory 标识。 为此,需要定义公共前缀下的设置,该前缀映射到触发器和绑定配置中的 connection 属性。

在此模式下,扩展需要以下属性:

属性 环境变量模板 说明 示例值
帐户终结点 <CONNECTION_NAME_PREFIX>__accountEndpoint Azure Cosmos DB 帐户终结点 URI。 https://<数据库帐户名称>.documents.azure.cn:443/

可以设置其他属性来自定义连接。 请参阅基于标识的连接的通用属性

在 Azure Functions 服务中托管时,基于标识的连接将使用托管标识。 默认情况下使用系统分配的标识,但可以使用 credentialclientID 属性来指定用户分配的标识。 在其他上下文(如本地开发)中运行时,将改用开发人员标识,尽管可以进行自定义。 请参阅使用基于标识的连接进行本地开发

向标识授予权限

无论使用何种标识,都必须具有执行所需操作的权限。 需要使用内置角色或者提供这些权限的自定义角色在 Azure RBAC 中分配角色

重要

某些权限可能由并非所有上下文都需要的目标服务公开。 尽可能遵循最低权限原则,仅授予标识所需的权限。 例如,如果应用只需要从数据源进行读取即可,则使用仅具有读取权限的角色。 分配一个也具有该服务写入权限的角色并不恰当,因为对于读取操作来说,写入是多余的权限。 同样,你也希望确保角色分配的范围仅限于需要读取的资源。

你将需要创建一个角色分配,以便在运行时提供对数据库帐户的访问权限。 所有者等管理角色还不够。 下表显示了在正常操作中使用 Cosmos DB 扩展时建议使用的内置角色。 根据所编写的代码,应用程序可能需要具有其他权限。

绑定类型 内置角色示例
触发器 Cosmos DB 内置数据参与者
输入绑定 Cosmos DB 内置数据读取者
输出绑定 Cosmos DB 内置数据参与者

异常和返回代码

绑定 参考
CosmosDB CosmosDB 错误代码

后续步骤