将 Node.js Mongoose 应用程序连接到 Azure Cosmos DB

适用对象: Mongodb

重要

你是否正在寻找一种数据库解决方案,以应对需要高扩展性、99.999% 可用性服务级别协议(SLA)、即时自动扩展和跨多个区域的自动故障转移的场景? 请考虑使用 Azure Cosmos DB for NoSQL

本教程演示在 Azure Cosmos DB 中存储数据时如何使用 Mongoose 框架。 它使用用于 MongoDB 的 Azure Cosmos DB API。 如果你不熟悉 Mongoose,它是 Node.js 中用于 MongoDB 的对象建模框架,提供了一种直接、基于模式的解决方案,用于对应用程序数据进行建模。

Cosmos DB 是世纪互联提供的多区域分布式多模型数据库服务。 可以快速创建和查询文档、键/值和图形数据库。 所有这些数据库都受益于Azure Cosmos DB核心的多区域分布和水平缩放功能。

先决条件

如果您没有 Azure 试用订阅,请在开始之前创建 试用订阅

可以创建一个 Azure Cosmos DB 免费层帐户,你将在帐户中获得前 1000 RU/s 的免费吞吐量和 25 GB 的免费存储。 还可以使用 URI 为 的 Azure Cosmos DB 模拟器。 有关在模拟器中使用的密钥,请参阅对请求进行身份验证

Node.js 版本 0.10.29 或更高版本。

创建 Azure Cosmos DB 帐户

创建Azure Cosmos DB帐户。 如果已经有想要使用的帐户,可以直接跳到“设置 Node.js 应用程序”。 如果使用 Azure Cosmos DB 模拟器,请按照 Azure Cosmos DB Emulator 中的步骤设置模拟器并跳到设置 Node.js 应用程序。

  1. 在新浏览器窗口中,登录到 Azure 门户

  2. 在左侧菜单中,选择“创建资源”。

    在 Azure 门户中创建资源的屏幕截图。

  3. 在“新建”页上,选择“数据库”>“Azure Cosmos DB”。

    Azure 门户“数据库”窗格的屏幕截图。

  4. 在“Azure Cosmos DB”页上,选择“创建”。

  5. 在“创建 Azure Cosmos DB 帐户”页中,输入新 Azure Cosmos DB 帐户的设置。

    设置 说明
    订阅 订阅名称 选择要用于此 Azure Cosmos DB 帐户的 Azure 订阅。
    资源组 资源组名称 选择一个资源组,或者选择“新建”,然后输入新资源组的唯一名称。
    帐户名 输入唯一的名称 输入标识此 Azure Cosmos DB 帐户的唯一名称。 帐户 URI 将是您的唯一帐户名称后附加“mongo.cosmos.azure.cn”。

    帐户名称只能使用小写字母、数字及连字符 (-),必须为 3 到 44 个字符长。
    位置 离用户最近的区域 选择用于托管 Azure Cosmos DB 帐户的地理位置。 使用离用户最近的位置,使他们能够以最快的速度访问数据。
    容量模式 预配吞吐量或无服务器 选择“预配吞吐量”以在预配吞吐量模式下创建帐户。 选择“无服务器”以在无服务器模式下创建帐户。

    注意:无服务器帐户仅支持 API for MongoDB 版本 4.2、4.0 和 3.6。 选择版本 3.2 将强制帐户处于配置的吞吐量模式。
    应用 Azure Cosmos DB 免费层折扣 “应用”或“不应用” 使用 Azure Cosmos DB 免费层,可以在帐户中免费获取前 1000 RU/秒和 25 GB 的存储空间。 了解有关免费层的更多信息。
    版本 选择所需的服务器版本 Azure Cosmos DB for MongoDB 与服务器版本 4.2、4.0、3.6 和 3.2 兼容。 创建帐户后,可以 升级或降级 帐户。

    注意

    每个 Azure 订阅可以拥有最多一个免费的 Azure Cosmos DB 帐户,并且你必须在创建帐户时选择加入。 如果未看到应用免费层折扣的选项,这意味着订阅中的另一个帐户已启用免费层。

    Azure Cosmos DB“新建帐户”页面的屏幕截图。

  6. 在“全局分发”选项卡中,配置以下详细信息。 对于本快速入门,可以保留默认值:

    设置 说明
    异地冗余 禁用 通过将你的区域与某个配对区域进行配对来启用或禁用帐户的多区域分发。 稍后可以将更多区域添加到帐户。
    多区域写入 禁用 借助多区域写入功能,可以利用全中国的数据库和容器的预配吞吐量。

    注意

    如果选择 “无服务器 ”作为 容量模式,则以下选项不可用:

    • 应用免费层折扣
    • 异地冗余
    • 多区域写入
  7. (可选)可以在以下选项卡中配置其他详细信息:

    • 网络 - 配置来自虚拟网络的访问
    • 备份策略- 配置定期连续备份策略。
    • 加密 - 使用服务管理的密钥或客户管理的密钥
    • 标记 - 标记是名称/值对,通过将相同的标记应用到多个资源和资源组,可以对资源进行分类并查看合并的账单。
  8. 选择“查看 + 创建”。

  9. 创建帐户需要几分钟时间。 等待门户中显示“祝贺你! Azure Cosmos DB for MongoDB 帐户已准备就绪”页面。

    Azure 门户“通知”窗格的屏幕截图。

创建数据库

本文介绍了在 Azure Cosmos DB 中创建集合的两种方法:

  • 将每个对象模型存储在单独的集合中:建议 创建具有专用吞吐量的数据库。 此容量模型可提高成本效益。

    Node.js 教程 - Azure 门户的屏幕截图,其中显示了如何在数据资源管理器中为 Azure Cosmos DB 帐户创建数据库,用于 Mongoose Node 模块

  • 将所有对象模型存储在单个Azure Cosmos DB集合中:如果希望将所有模型存储在单个集合中,请创建新的数据库,而无需选择“预配吞吐量”选项。 对于每种对象模型,此容量模型都会为每个集合创建其各自独立的吞吐量容量。

创建数据库后,将在以下部分中的 COSMOSDB_DBNAME 环境变量中使用名称。

设置 Node.js 应用程序

注意

如果要演练示例代码而不是设置应用程序,请克隆本教程中使用的示例,并在Azure Cosmos DB上生成 Node.js Mongoose 应用程序。

  1. 若要在所选的文件夹中创建 Node.js 应用程序,请在 node 命令提示符下运行以下命令。

    npm init

    回答问题后,你的项目已准备就绪。

  2. 将一个新文件添加到该文件夹,并将此文件命名为 index.js

  3. 使用以下选项中的 npm install 一种安装必要的软件包:

    • Mongoose:

    注意

    有关与您的 API for MongoDB 服务器版本兼容的 Mongoose 版本的详细信息,请参阅 Mongoose 兼容性

    • Dotenv(如果要从 .env 文件加载机密)npm install dotenv --save

      注意

      --save 标志将依赖项添加到 package.json 文件。

  4. 导入 index.js 文件中的依赖项。

    var mongoose = require('mongoose');
    var env = require('dotenv').config();   //Use the .env file to load the variables
    
  5. 将 Azure Cosmos DB 的连接字符串和 Azure Cosmos DB 的名称添加到 .env 文件中。 将占位符{cosmos-account-name}{dbname}替换为自己的Azure Cosmos DB帐户名称和数据库名称,而不用大括号符号。

    // You can get the following connection details from the Azure portal. You can find the details on the Connection string pane of your Azure Cosmos DB account.
    
    COSMOSDB_USER = "<Azure Cosmos DB account's user name, usually the database account name>"
    COSMOSDB_PASSWORD = "<Azure Cosmos DB account password, this is one of the keys specified in your account>"
    COSMOSDB_DBNAME = "<Azure Cosmos DB database name>"
    COSMOSDB_HOST= "<Azure Cosmos DB Host name>"
    COSMOSDB_PORT=10255
    
  6. 使用 Mongoose 框架连接到Azure Cosmos DB。 将以下代码添加到末尾 index.js

    mongoose.connect("mongodb://"+process.env.COSMOSDB_HOST+":"+process.env.COSMOSDB_PORT+"/"+process.env.COSMOSDB_DBNAME+"?ssl=true& replicaSet=globaldb", {
       auth: {
         username: process.env.COSMOSDB_USER,
         password: process.env.COSMOSDB_PASSWORD
       },
       useNewUrlParser: true,
       useUnifiedTopology: true,
       retryWrites: false
    })
    .then(() => console.log('Connection to CosmosDB successful'))
    .catch((err) => console.error(err));
    

    注意

    此处,使用 process.env.{variableName} npm 包中的 dotenv 加载环境变量。

    连接到Azure Cosmos DB后,可以开始在 Mongoose 中设置对象模型。

将 Mongoose 与 Azure Cosmos DB 配合使用的最佳做法

对于你创建的每个模型,Mongoose 会创建新的集合。 可以使用 “数据库级别吞吐量”选项更改此行为。 若要使用单个集合,请使用 Mongoose 鉴别器。 鉴别器是架构继承机制。 在同一个底层 MongoDB 集合上,您可以创建多个具有重叠模式的模型。

可将各种数据模型存储在同一集合中,然后在查询时使用筛选子句,只提取所需的数据。 让我们来看看每个模型。

每个对象模型对应一个集合

本部分介绍如何使用用于 MongoDB 的 Azure Cosmos DB API 设置此配置。 此方法是推荐的方法,因为它可让你控制成本和容量。 因此,数据库上的请求单位数不依赖于对象模型的数量。 此配置是 Mongoose 的默认操作模型,因此你可能熟悉它。

  1. 再次打开文件 index.js

  2. 为“Family”创建架构定义。

    const Family = mongoose.model('Family', new mongoose.Schema({
        lastName: String,
        parents: [{
            familyName: String,
            firstName: String,
            gender: String
        }],
        children: [{
            familyName: String,
            firstName: String,
            gender: String,
            grade: Number
        }],
        pets:[{
            givenName: String
        }],
        address: {
            country: String,
            state: String,
            city: String
        }
    }));
    
  3. 为“Family”创建对象。

    const family = new Family({
        lastName: "Volum",
        parents: [
            { firstName: "Thomas" },
            { firstName: "Mary Kay" }
        ],
        children: [
            { firstName: "Ryan", gender: "male", grade: 8 },
            { firstName: "Patrick", gender: "male", grade: 7 }
        ],
        pets: [
            { givenName: "Buddy" }
        ],
        address: { country: "USA", state: "WA", city: "Seattle" }
    });
    
  4. 将对象保存到Azure Cosmos DB。 此操作将创建集合。

    family.save((err, saveFamily) => {
        console.log(JSON.stringify(saveFamily));
    });
    
  5. 创建另一个架构和对象。 这次,为 Vacation Destinations 创建一个家庭可能会感兴趣的内容。

    1. 与上次一样,创建架构。

      const VacationDestinations = mongoose.model('VacationDestinations', new mongoose.Schema({
       name: String,
       country: String
      }));
      
    2. 创建示例对象(可以将多个对象添加到此架构),并保存它。

    const vacaySpot = new VacationDestinations({
     name: "Honolulu",
     country: "USA"
    });
    
    vacaySpot.save((err, saveVacay) => {
     console.log(JSON.stringify(saveVacay));
    });
    
  6. 现在,在Azure门户中,会看到在Azure Cosmos DB中创建的两个集合。

    Node.js 教程 - Azure 门户的屏幕截图,其中显示 Azure Cosmos DB 帐户,并突出显示了多个集合名称 - Node 数据库

  7. 最后,从Azure Cosmos DB读取数据。 由于你使用的是默认的 Mongoose 运行模型,因此读取操作与 Mongoose 中的其他读取操作完全相同。

    Family.find({ 'children.gender' : "male"}, function(err, foundFamily){
        foundFamily.forEach(fam => console.log("Found Family: " + JSON.stringify(fam)));
    });
    

使用 Mongoose 鉴别器将数据存储在单个集合中

此方法使用 Mongoose 鉴别器 来帮助优化每个集合的成本。 使用鉴别器可以定义区分键,从而可以存储、区分和筛选不同的对象模型。

在此方法中,你将创建一个基础对象模型,定义一个区分键,并将 VacationDestinationsFamily 作为扩展添加到基础模型中。

  1. 设置基本配置并定义歧视性密钥。

    const baseConfig = {
        discriminatorKey: "_type", //If you've got a lot of different data types, you could also consider setting up a secondary index here.
        collection: "alldata"   //Name of the Common Collection
    };
    
  2. 定义通用对象模型。

    const commonModel = mongoose.model('Common', new mongoose.Schema({}, baseConfig));
    
  3. 定义 Family 模型。 请注意,您使用的是 commonModel.discriminator,而不是 mongoose.model。 此外,你还需要将基本配置添加到 mongoose schema 中。 因此,歧视性密钥是 FamilyType

    const Family_common = commonModel.discriminator('FamilyType', new     mongoose.Schema({
        lastName: String,
        parents: [{
            familyName: String,
            firstName: String,
            gender: String
        }],
        children: [{
            familyName: String,
            firstName: String,
           gender: String,
            grade: Number
        }],
        pets:[{
            givenName: String
        }],
        address: {
            country: String,
            state: String,
            city: String
        }
    }, baseConfig));
    
  4. 再添加一个架构,这次是针对 VacationDestinations 模型的。 歧视性密钥是 VacationDestinationsType

    const Vacation_common = commonModel.discriminator('VacationDestinationsType', new mongoose.Schema({
        name: String,
        country: String
    }, baseConfig));
    
  5. 为模型创建对象并将其保存。

    1. 将对象添加到 Family 模型。

      const family_common = new Family_common({
       lastName: "Volum",
       parents: [
           { firstName: "Thomas" },
           { firstName: "Mary Kay" }
       ],
       children: [
           { firstName: "Ryan", gender: "male", grade: 8 },
           { firstName: "Patrick", gender: "male", grade: 7 }
       ],
       pets: [
           { givenName: "Buddy" }
       ],
       address: { country: "USA", state: "WA", city: "Seattle" }
      });
      
      family_common.save((err, saveFamily) => {
       console.log("Saved: " + JSON.stringify(saveFamily));
      });
      
      1. 将对象添加到 VacationDestinations 模型并保存。
      const vacay_common = new Vacation_common({
       name: "Honolulu",
       country: "USA"
      });
      
      vacay_common.save((err, saveVacay) => {
       console.log("Saved: " + JSON.stringify(saveVacay));
      });
      
  6. 现在,如果返回到 Azure 门户,你会看到只有一个名为 Family 的集合,其中包含 alldataVacationDestinations 两种数据。

    Node.js 教程 - Azure 门户的屏幕截图,其中显示 Azure Cosmos DB 帐户,并突出显示了集合名称 - Node 数据库

  7. 请注意,每个对象都有另一个名为的属性 __type,这有助于区分两个不同的对象模型。

  8. 最后,读取存储在Azure Cosmos DB中的数据。 Mongoose 会负责根据模型筛选数据。 因此,读取数据时无需执行任何不同操作。 只需指定你的模型(本例中为 Family_common),Mongoose 就会在 DiscriminatorKey 上处理筛选。

    Family_common.find({ 'children.gender' : "male"}, function(err, foundFamily){
        foundFamily.forEach(fam => console.log("Found Family (using discriminator): " + JSON.stringify(fam)));
    });
    

正如你所看到的,使用 Mongoose 鉴别器很容易。 如果你有使用 Mongoose 框架的应用,本教程将帮助你使用适用于 MongoDB 的 Azure Cosmos DB API 启动和运行应用程序,而无需进行太多更改。

清理资源

执行完应用和 Azure Cosmos DB 帐户的操作以后,可以删除所创建的 Azure 资源,以免产生更多费用。 若要删除资源,请执行以下操作:

  1. 在 Azure 门户的“搜索”栏中,搜索并选择“资源组”。

  2. 从列表中选择为本快速入门创建的资源组。

    选择要删除的资源组

  3. 在资源组“概览”页上,选择“删除资源组”。

    删除资源组

  4. 在下一窗口中输入要删除的资源组的名称,然后选择“删除”。

后续步骤

  • 了解如何将 Studio 3T 与 Azure Cosmos DB 的用于 MongoDB 的 API 配合使用。
  • 了解如何将 Robo 3T 与 Azure Cosmos DB 的用于 MongoDB 的 API 配合使用。
  • 通过 Azure Cosmos DB 的用于 MongoDB 的 API 来浏览 MongoDB 示例
  • 正在为迁移到 Azure Cosmos DB 进行容量规划? 使用有关现有数据库群集的信息进行容量规划。
    • 如果仅知道现有数据库群集中的 vcore 数和服务器数,请阅读有关 使用 vCore 或 vCPU 估算请求单位的信息。
    • 如果知道当前数据库工作负载的典型请求速率,请阅读有关使用 Azure Cosmos DB 容量规划工具估计请求单位的信息。