在 Azure Cosmos DB for NoSQL SDK 中对叉积查询结果进行分页

Azure Cosmos DB 查询通常会有多页的结果。 当 Azure Cosmos DB 不能在单次执行中返回所有查询结果时,分页会在服务器端自动完成。 在许多应用程序中,你需要使用 SDK 编写代码,以高性能的方式分批处理查询结果。

在本实验室中,你将创建一个可在循环中使用的源迭代器,用来循环访问整个结果集。

准备开发环境

如果你还没有将 DP-420 的实验室代码存储库克隆到使用此实验室的环境,请按照以下步骤操作。 否则,请在 Visual Studio Code 中打开以前克隆的文件夹。

  1. 启动 Visual Studio Code。

    📝 如果你还不熟悉 Visual Studio Code 界面,请参阅 Visual Studio Code 入门指南

  2. 打开命令面板并运行 Git: Clone,将 https://github.com/microsoftlearning/dp-420-cosmos-db-dev GitHub 存储库克隆到你选择的本地文件夹中。

    💡 你可以使用 Ctrl+Shift+P 键盘快捷方式打开命令面板。

  3. 克隆存储库后,打开在 Visual Studio Code 中选择的本地文件夹。

创建 Azure Cosmos DB for NoSQL 帐户

Azure Cosmos DB 是一项基于云的 NoSQL 数据库服务,它支持多个 API。 在首次预配 Azure Cosmos DB 帐户时,可以选择希望该帐户支持的 API(例如 Mongo API 或 NoSQL API)。 完成 Azure Cosmos DB for NoSQL 帐户预配后,可以检索终结点和密钥,并使用它们通过 Azure SDK for .NET 或所选择的任何其他 SDK 连接到 Azure Cosmos DB for NoSQL 帐户。

  1. 在新的 Web 浏览器窗口或选项卡中,导航到 Azure 门户 (portal.azure.com)。

  2. 使用与你的订阅关联的 Microsoft 凭证登录到门户。

  3. 选择“+ 创建资源”,搜索“Cosmos DB”,然后使用以下设置创建新的“Azure Cosmos DB for NoSQL”帐户资源,并将所有其余设置保留为默认值:

    设置
    订阅 你的现有 Azure 订阅
    资源组 选择现有资源组,或创建新资源组
    帐户名 输入全局唯一名称
    位置 选择任何可用区域
    容量模式 预配的吞吐量
    应用免费分级折扣 不应用

    📝 你的实验室环境可能存在阻止你创建新资源组的限制。 如果是这种情况,请使用现有的预先创建的资源组。

  4. 等待部署任务完成,然后继续执行此任务。

  5. 转到新创建的 Azure Cosmos DB 帐户资源,并导航到“键”窗格。

  6. 此窗格包含从 SDK 连接到帐户所需的连接详细信息和凭据。 具体而言:

    1. 请注意“URI”** 字段。 稍后在本练习中将用到此终结点值。

    2. 请注意“主键”** 字段。 稍后在本练习中将用到此键值。

  7. 返回到 Visual Studio Code

使用数据为 Azure Cosmos DB for NoSQL 帐户设定种子

cosmicworks 命令行工具将示例数据部署到任何 Azure Cosmos DB for NoSQL 帐户。 该工具是开源工具,可通过 NuGet 获得。 将此工具安装到 Azure Cloud Shell,然后使用它来设定数据库种子。

  1. 在 Visual Studio Code 中,打开“终端”菜单,然后选择“新建终端”以打开新的终端实例 。

  2. 在计算机上安装可全局使用的 cosmicworks 命令行工具。

     dotnet tool install cosmicworks --global --version 1.*
    

    💡 此命令可能需要几分钟时间才能完成。 如果你过去已经安装了此工具的最新版本,此命令将输出警告消息(*工具 “cosmicworks” 已安装)。

  3. 使用以下命令行选项运行 cosmicworks 以设置 Azure Cosmos DB 种子帐户:

    选项
    –endpoint 之前在本实验室中复制的终结点值
    –key 之前在本实验室中复制的键值
    –datasets product
     cosmicworks --endpoint <cosmos-endpoint> --key <cosmos-key> --datasets product
    

    📝 例如,如果终结点为:https­://dp420.documents.azure.com:443/,密钥为:fDR2ci9QgkdkvERTQ==,则命令为:cosmicworks --endpoint https://dp420.documents.azure.com:443/ --key fDR2ci9QgkdkvERTQ== --datasets product

  4. 等待 cosmicworks 命令完成对帐户的数据库、容器和项的填充。

  5. 关闭集成终端。

使用 SDK 对小型 SQL 查询结果集进行分页

处理查询结果时,必须确保代码处理所有结果页面,并在发出后续请求之前检查是否还有任何其他页面。

  1. 在 Visual Studio Code** 的“资源管理器”** 窗格中,浏览到“10-paginate-results-sdk”** 文件夹。

  2. 打开 product.cs 代码文件。

  3. 观察 Product 类及其对应的属性。 具体而言,此实验室将使用 id、name 和 price 属性。

  4. 返回到 Visual Studio Code 的“资源管理器”窗格,打开 script.cs 代码文件。

  5. 更新名为 endpoint 的现有变量,将其值设置为前面创建的 Azure Cosmos DB 帐户的终结点 。

     string endpoint = "<cosmos-endpoint>";
    

    📝 例如,如果终结点为:https­://dp420.documents.azure.com:443/,则 C# 语句将为:string endpoint = “https­://dp420.documents.azure.com:443/”;。

  6. 更新名为 key 的现有变量,将其值设置为前面创建的 Azure Cosmos DB 帐户的键 。

     string key = "<cosmos-key>";
    

    📝 例如,如果键为:fDR2ci9QgkdkvERTQ==,则 C# 语句应为:string key = “fDR2ci9QgkdkvERTQ==”;。

  7. 使用 SELECT p.id, p.name, p.price FROM products p 的值创建一个名为 sql 的 string 类型的新变量****

     string sql = "SELECT p.id, p.name, p.price FROM products p ";
    
  8. 创建一个 QueryDefinition 类型的新变量,并传入 sql 变量作为构造函数的参数:

     QueryDefinition query = new (sql);
    
  9. 使用默认空构造函数创建名为 options**QueryRequestOptions 类型的新变量:

     QueryRequestOptions options = new ();
    
  10. 将 options** 变量的 MaxItemCount 属性设置为值 50**:

     options.MaxItemCount = 50;
    
  11. 通过调用 Container 类的泛型 GetItemQueryIterator 方法,创建一个名为 iterator** 的 FeedIterator<> 类型的新变量,将 query** 和 options** 变量作为参数传入:

     FeedIterator<Product> iterator = container.GetItemQueryIterator<Product>(query, requestOptions: options);
    
  12. 创建一个 while** 循环,用于检查 iterator** 变量的 HasMoreResults 属性:

     while (iterator.HasMoreResults)
     {
            
     }
    
  13. 在 while** 循环中,使用 Product** 类异步调用 iterator** 变量的 ReadNextAsync 方法,将结果存储在泛型类型 FeedResponse 的名为 products** 的变量中:

     FeedResponse<Product> products = await iterator.ReadNextAsync();
    
  14. 同样在 while** 循环中,通过使用变量 product** 循环访问 products** 变量来表示 Product** 类型的实例,创建新的 foreach** 循环:

     foreach (Product product in products)
     {
    
     }
    
  15. 在 foreach** 循环中,使用内置的 Console.WriteLine** 静态方法格式化并输出 product** 变量的 id、name** 和 price** 属性:

     Console.WriteLine($"[{product.id}]\t[{product.name,40}]\t[{product.price,10}]");
    
  16. 返回到 while** 循环中,使用内置的 Console.WriteLine** 静态方法输出消息“按任意键获取更多结果”**:

     Console.WriteLine("Press any key to get more results");
    
  17. 同样在 while** 循环中,使用内置的 Console.ReadKey** 静态方法侦听下一个按键输入:

     Console.ReadKey();
    
  18. 完成后,代码文件现在应包含:

     using System;
     using Microsoft.Azure.Cosmos;
    
     string endpoint = "<cosmos-endpoint>";
    
     string key = "<cosmos-key>";
    
     CosmosClient client = new CosmosClient(endpoint, key);
    
     Database database = await client.CreateDatabaseIfNotExistsAsync("cosmicworks");
    
     Container container = await database.CreateContainerIfNotExistsAsync("products", "/categoryId");
    
     string sql = "SELECT p.id, p.name, p.price FROM products p ";
     QueryDefinition query = new (sql);
    
     QueryRequestOptions options = new ();
     options.MaxItemCount = 50;
    
     FeedIterator<Product> iterator = container.GetItemQueryIterator<Product>(query, requestOptions: options);
    
     while (iterator.HasMoreResults)
     {
         FeedResponse<Product> products = await iterator.ReadNextAsync();
         foreach (Product product in products)
         {
             Console.WriteLine($"[{product.id}]\t[{product.name,40}]\t[{product.price,10}]");
         }
    
         Console.WriteLine("Press any key for next page of results");
         Console.ReadKey();        
     }
    
  19. 保存 script.cs 文件。

  20. 在 Visual Studio Code** 中,打开 10-paginate-results-sdk** 文件夹的上下文菜单,然后选择“在集成终端中打开”** 以打开一个新的终端实例。

  21. 使用 dotnet run 命令生成并运行项目:

     dotnet run
    
  22. 该脚本现在将输出与查询匹配的第一组 50 个项。 按任意键获取下一组 50 个项,直到查询循环访问完所有匹配项。

    💡 查询将匹配 products 容器中的数百个项。

  23. 关闭集成终端。

  24. 关闭 Visual Studio Code。