将 Node.js Mongoose 应用程序连接到 Azure Cosmos DBConnect a Node.js Mongoose application to Azure Cosmos DB

本教程演示在 Cosmos DB 中存储数据时如何使用 Mongoose 框架This tutorial demonstrates how to use the Mongoose Framework when storing data in Cosmos DB. 本演练使用 Azure Cosmos DB 的用于 MongoDB 的 API。We use the Azure Cosmos DB's API for MongoDB for this walkthrough. 不熟悉该接口的读者应知道,Mongoose 是 Node.js 中适用于 MongoDB 的对象建模框架,提供简单直接的、基于架构的解决方案来为应用程序数据建模。For those of you unfamiliar, Mongoose is an object modeling framework for MongoDB in Node.js and provides a straight-forward, schema-based solution to model your application data.

Azure Cosmos DB 是世纪互联提供的多区域分布式多模型数据库服务。Azure Cosmos DB is 21Vianet's multiple-regionally distributed multi-model database service. 可快速创建和查询文档、键/值和图形数据库,所有这些都受益于 Cosmos DB 核心的多区域分布和水平缩放功能。You can quickly create and query document, key/value, and graph databases, all of which benefit from the multiple-region distribution and horizontal scale capabilities at the core of Cosmos DB.

先决条件Prerequisites

如果没有 Azure 订阅,可在开始前创建一个试用帐户If you don't have an Azure subscription, create a trial account before you begin.

可以使用 URI 为 https://localhost:8081Azure Cosmos DB 模拟器You can use the Azure Cosmos DB Emulator with a URI of https://localhost:8081. 有关在模拟器中使用的密钥,请参阅对请求进行身份验证For the key to use with the emulator, see Authenticating requests.

Node.js 版本 v0.10.29 或更高版本。Node.js version v0.10.29 or higher.

创建 Cosmos 帐户Create a Cosmos account

让我们创建 Cosmos 帐户。Let's create a Cosmos account. 如果已经有想要使用的帐户,可以直接跳到“设置 Node.js 应用程序”。If you already have an account you want to use, you can skip ahead to Set up your Node.js application. 如果使用 Azure Cosmos DB 仿真器,请遵循 Azure Cosmos DB 仿真器中的步骤设置该仿真器,并直接跳到“设置 Node.js 应用程序”。If you are using the Azure Cosmos DB Emulator, follow the steps at Azure Cosmos DB Emulator to set up the emulator and skip ahead to Set up your Node.js application.

  1. 在新浏览器窗口中,登录到 Azure 门户In a new browser window, sign in to the Azure portal.

  2. 在左侧菜单中,选择“创建资源” 。In the left menu, select Create a resource.

    在 Azure 门户中创建资源

  3. 在“新建”页上,选择“数据库” > “Azure Cosmos DB”。 On the New page, select Databases > Azure Cosmos DB.

    Azure 门户“数据库”窗格

  4. 在“创建 Azure Cosmos DB 帐户”页中,输入新 Azure Cosmos DB 帐户的设置 。On the Create Azure Cosmos DB Account page, enter the settings for the new Azure Cosmos DB account.

    设置Setting Value 说明Description
    订阅Subscription 你的订阅Your subscription 选择要用于此 Azure Cosmos DB 帐户的 Azure 订阅。Select the Azure subscription that you want to use for this Azure Cosmos DB account.
    资源组Resource Group 新建Create new

    然后,输入与帐户名称相同的名称。Then enter the same name as Account Name
    选择“新建”。 Select Create new. 然后输入帐户的新资源组名称。Then enter a new resource group name for your account. 为简单起见,请使用与 Azure Cosmos DB 帐户名称相同的名称。For simplicity, use the same name as your Azure Cosmos DB account name.
    帐户名Account Name 输入唯一的名称Enter a unique name 输入标识此 Azure Cosmos DB 帐户的唯一名称。Enter a unique name to identify your Azure Cosmos DB account. 帐户 URI 将是追加到唯一帐户名称的“mongo.cosmos.azure.cn” 。Your account URI will be mongo.cosmos.azure.cn appended to your unique account name.

    帐户名称只能使用小写字母、数字及连字符 (-),必须为 3 到 31 个字符长。The account name can use only lowercase letters, numbers, and hyphens (-), and must be between 3 and 31 characters long.
    APIAPI Azure Cosmos DB for Mongo DB APIAzure Cosmos DB for Mongo DB API API 确定要创建的帐户的类型。The API determines the type of account to create. Azure Cosmos DB 提供五种 API:适用于文档数据库的 Core (SQL)、适用于图形数据库的 Gremlin、适用于文档数据库的 Azure Cosmos DB for Mongo DB API、Azure 表和 Cassandra。Azure Cosmos DB provides five APIs: Core (SQL) for document databases, Gremlin for graph databases, Azure Cosmos DB for Mongo DB API for document databases, Azure Table, and Cassandra. 目前,你必须为每种 API 创建单独的帐户。Currently, you must create a separate account for each API.

    选择“Azure Cosmos DB for Mongo DB API”,因为本快速入门将创建使用 MongoDB 的集合 。Select Azure Cosmos DB for Mongo DB API because in this quickstart you are creating a collection that works with MongoDB.

    了解有关 Azure Cosmos DB for MongoDB API 的详细信息Learn more about Azure Cosmos DB for MongoDB API.
    位置Location 选择离用户最近的区域Select the region closest to your users 选择用于托管 Azure Cosmos DB 帐户的地理位置。Select a geographic location to host your Azure Cosmos DB account. 使用离用户最近的位置,使他们能够以最快的速度访问数据。Use the location that's closest to your users to give them the fastest access to the data.

    选择“查看 + 创建” 。Select Review+Create. 可以跳过“网络” 和“标记” 部分。You can skip the Network and Tags section.

    Azure Cosmos DB 的“新建帐户”页

  5. 创建帐户需要几分钟时间。The account creation takes a few minutes. 等待门户中显示“祝贺你! Azure Cosmos DB for MongoDB 帐户已准备就绪”页。Wait for the portal to display the Congratulations! Your Azure Cosmos DB for Mongo DB API account is ready page.

    Azure 门户“通知”窗格

创建数据库Create a database

在此应用程序中,我们将介绍在 Azure Cosmos DB 中创建集合的两种方法:In this application we will cover two ways of creating collections in Azure Cosmos DB:

  • 将每个对象模型存储在一个单独的集合中:建议创建具有专用吞吐量的数据库Storing each object model in a separate collection: We recommend creating a database with dedicated throughput. 使用此容量模型会更为经济高效。Using this capacity model will give you better cost efficiency.

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

  • 将所有对象模型存储在单个 Cosmos DB 集合中:如果希望将所有模型存储在单个集合中,只需在不选择“预配吞吐量”选项的情况下创建新数据库即可。Storing all object models in a single Cosmos DB collection: If you'd prefer to store all models in a single collection, you can just create a new database without selecting the Provision Throughput option. 使用此容量模型时,将为每个对象模型创建每个具有自己的吞吐容量的集合。Using this capacity model will create each collection with its own throughput capacity for every object model.

创建数据库后,将在下面的 COSMOSDB_DBNAME 环境变量中使用此名称。After you create the database, you'll use the name in the COSMOSDB_DBNAME environment variable below.

设置 Node.js 应用程序Set up your Node.js application

备注

如果只想演练示例代码而不是设置应用程序本身,请克隆本教程使用的示例,并在 Azure Cosmos DB 上生成 Node.js Mongoose 应用程序。If you'd like to just walkthrough the sample code instead of setup the application itself, clone the sample used for this tutorial and build your Node.js Mongoose application on Azure Cosmos DB.

  1. 若要在所选的文件夹中创建 Node.js 应用程序,请在 node 命令提示符下运行以下命令。To create a Node.js application in the folder of your choice, run the following command in a node command prompt.

    npm init

    回答以下问题,然后即可开始创建项目。Answer the questions and your project will be ready to go.

  2. 将一个新文件添加到该文件夹,并将此文件命名为 index.jsAdd a new file to the folder and name it index.js.

  3. 使用一个 npm install 选项安装所需的包:Install the necessary packages using one of the npm install options:

    • Mongoose:npm install mongoose@5 --saveMongoose: npm install mongoose@5 --save

      备注

      下面的 Mongoose 示例连接基于 Mongoose 5+,后者自早期版本以来已发生变化。The Mongoose example connection below is based on Mongoose 5+, which has changed since earlier versions.

    • Dotenv(若要从 .env 文件加载机密):npm install dotenv --saveDotenv (if you'd like to load your secrets from an .env file): npm install dotenv --save

      备注

      --save 标志将依赖项添加到 package.json 文件。The --save flag adds the dependency to the package.json file.

  4. 导入 index.js 文件中的依赖项。Import the dependencies in your index.js file.

    var mongoose = require('mongoose');
    var env = require('dotenv').config();   //Use the .env file to load the variables
    
  5. 将 Cosmos DB 连接字符串和 Cosmos DB 名称添加到 .env 文件。Add your Cosmos DB connection string and Cosmos DB Name to the .env file. 将占位符 {cosmos-account-name} 和 {dbname} 替换为你自己的 Cosmos 帐户名称和数据库名称,不要带大括号符号。Replace the placeholders {cosmos-account-name} and {dbname} with your own Cosmos account name and database name, without the brace symbols.

    # 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 account.
    
    COSMODDB_USER = "<Azure Cosmos account's user name, usually the database account name>"
    COSMOSDB_PASSWORD = "<Azure Cosmos account password, this is one of the keys specified in your account>"
    COSMOSDB_DBNAME = "<Azure Cosmos database name>"
    COSMOSDB_HOST= "<Azure Cosmos Host name>"
    COSMOSDB_PORT=10255
    
  6. 将以下代码添加到 index.js 末尾,以使用 Mongoose 框架连接到 Cosmos DB。Connect to Cosmos DB using the Mongoose framework by adding the following code to the end of index.js.

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

    备注

    此处的环境变量是使用“dotenv”npm 包以 process.env.{variableName} 加载的。Here, the environment variables are loaded using process.env.{variableName} using the 'dotenv' npm package.

    连接到 Azure Cosmos DB 后,可以在 Mongoose 中立即开始设置对象模型。Once you are connected to Azure Cosmos DB, you can now start setting up object models in Mongoose.

将 Mongoose 与 Cosmos DB 配合使用的最佳做法Best practices for using Mongoose with Cosmos DB

对于你创建的每个模型,Mongoose 会创建新的集合。For every model you create, Mongoose creates a new collection. 解决此问题的最好方法是使用前面讨论的数据库级吞吐量选项This is best addressed using the Database Level Throughput option, which was previously discussed. 若要使用单个集合,需要使用 Mongoose 鉴别器To use a single collection, you need to use Mongoose Discriminators. 鉴别器是架构继承机制。Discriminators are a schema inheritance mechanism. 使用鉴别器可在同一底层 MongoDB 集合的底层创建多个具有重叠架构的模型。They enable you to have multiple models with overlapping schemas on top of the same underlying MongoDB collection.

可将各种数据模型存储在同一集合中,然后在查询时使用筛选子句,只提取所需的数据。You can store the various data models in the same collection and then use a filter clause at query time to pull down only the data needed. 让我们来看看每个模型。Let's walk through each of the models.

每个对象模型一个集合One collection per object model

本部分探讨如何使用 Azure Cosmos DB 的用于 MongoDB 的 API 实现此目的。This section explores how to achieve this with Azure Cosmos DB's API for MongoDB. 此方法是我们建议的方法,因为它可以控制成本和容量。This method is our recommended approach since it allows you to control cost and capacity. 因此,数据库上的请求单位数量不取决于对象模型的数量。As a result, the amount of Request Units on the database does not depend on the number of object models. 这是 Mongoose 的默认操作模型,因此,你可能熟悉此模型。This is the default operating model for Mongoose, so, you might be familiar with this.

  1. 再次打开 index.jsOpen your index.js again.

  2. 为“Family”创建架构定义。Create the schema definition for '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”创建对象。Create an object for '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. 最后,将对象保存到 Cosmos DB。Finally, let's save the object to Cosmos DB. 这会在幕后创建一个集合。This creates a collection underneath the covers.

    family.save((err, saveFamily) => {
        console.log(JSON.stringify(saveFamily));
    });
    
  5. 现在,我们创建另一个架构和对象。Now, let's create another schema and object. 这一次,我们要针对家庭成员可能感兴趣的“Vacation Destinations”创建一个架构。This time, let's create one for 'Vacation Destinations' that the families might be interested in.

    1. 我们按前面所述创建方案Just like last time, let's create the scheme

      const VacationDestinations = mongoose.model('VacationDestinations', new mongoose.Schema({
      name: String,
      country: String
      }));
      
    2. 创建示例对象(可将多个对象添加到此架构)并将其保存。Create a sample object (You can add multiple objects to this schema) and save it.

      const vacaySpot = new VacationDestinations({
      name: "Honolulu",
      country: "USA"
      });
      
      vacaySpot.save((err, saveVacay) => {
      console.log(JSON.stringify(saveVacay));
      });
      
  6. 现在,请转到 Azure 门户,可以看到 Cosmos DB 中创建了两个集合。Now, going into the Azure portal, you notice two collections created in Cosmos DB.

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

  7. 最后,我们从 Cosmos DB 读取数据。Finally, let's read the data from Cosmos DB. 由于我们使用的是默认 Mongoose 操作模型,读取操作与 Mongoose 的其他读取操作相同。Since we're using the default Mongoose operating model, the reads are the same as any other reads with Mongoose.

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

使用 Mongoose 鉴别器在单个集合中存储数据Using Mongoose discriminators to store data in a single collection

在此方法中,我们使用 Mongoose 鉴别器来帮助优化每个集合的成本。In this method, we use Mongoose Discriminators to help optimize for the costs of each collection. 使用鉴别器可以定义区分的“键”,使用该键可以存储、区分和筛选不同的对象模型。Discriminators allow you to define a differentiating 'Key', which allows you to store, differentiate and filter on different object models.

我们将在此处创建一个基对象模型、定义区分键,并将“Family”和“VacationDestinations”作为扩展添加到基模型。Here, we create a base object model, define a differentiating key and add 'Family' and 'VacationDestinations' as an extension to the base model.

  1. 让我们设置基本配置并定义鉴别器键。Let's set up the base config and define the discriminator key.

    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. 接下来,定义通用对象模型Next, let's define the common object model

    const commonModel = mongoose.model('Common', new mongoose.Schema({}, baseConfig));
    
  3. 现在定义“Family”模型。We now define the 'Family' model. 请注意,我们使用的是 commonModel.discriminator 而不是 mongoose.modelNotice here that we're using commonModel.discriminator instead of mongoose.model. 此外,我们还要将基本配置添加到 mongoose 架构。Additionally, we're also adding the base config to the mongoose schema. 因此,此处的 discriminatorKey 是 FamilyTypeSo, here, the discriminatorKey is 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”添加的。Similarly, let's add another schema, this time for the 'VacationDestinations'. 此处的 DiscriminatorKey 是 VacationDestinationsTypeHere, the DiscriminatorKey is VacationDestinationsType.

    const Vacation_common = commonModel.discriminator('VacationDestinationsType', new mongoose.Schema({
        name: String,
        country: String
    }, baseConfig));
    
  5. 最后,创建模型的对象并将其保存。Finally, let's create objects for the model and save it.

    1. 将对象添加到“Family”模型。Let's add object(s) to the 'Family' model.

      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));
      });
      
    2. 接下来,将对象添加到“VacationDestinations”模型,并将其保存。Next, let's add object(s) to the 'VacationDestinations' model and save it.

      const vacay_common = new Vacation_common({
      name: "Honolulu",
      country: "USA"
      });
      
      vacay_common.save((err, saveVacay) => {
      console.log("Saved: " + JSON.stringify(saveVacay));
      });
      
  6. 现在,如果返回到 Azure 门户,可以看到只有一个名为 alldata 的集合,其中包含“Family”和“VacationDestinations”数据。Now, if you go back to the Azure portal, you notice that you have only one collection called alldata with both 'Family' and 'VacationDestinations' data.

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

  7. 另请注意,每个对象有另一个名为 __type 的属性,可帮助区分两个不同的对象模型。Also, notice that each object has another attribute called as __type, which help you differentiate between the two different object models.

  8. 最后,读取存储在 Azure Cosmos DB 中的数据。Finally, let's read the data that is stored in Azure Cosmos DB. Mongoose 会负责根据模型筛选数据。Mongoose takes care of filtering data based on the model. 因此,在读取数据时,无需执行其他任何操作。So, you have to do nothing different when reading data. 只需指定模型(在本例中为 Family_common),Mongoose 就会根据“DiscriminatorKey”处理筛选。Just specify your model (in this case, Family_common) and Mongoose handles filtering on the 'DiscriminatorKey'.

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

可以看到,Mongoose 鉴别器的用法非常简单。As you can see, it is easy to work with Mongoose discriminators. 如果你的某个应用使用 Mongoose 框架,可以根据本教程中所述的方法,让该应用程序使用 Azure Cosmos 的用于 MongoDB 的 API 启动并运行,无需做出过多的更改。So, if you have an app that uses the Mongoose framework, this tutorial is a way for you to get your application up and running using Azure Cosmos's API for MongoDB without requiring too many changes.

清理资源Clean up resources

执行完应用和 Azure Cosmos DB 帐户的操作以后,可以删除所创建的 Azure 资源,以免产生更多费用。When you're done with your app and Azure Cosmos DB account, you can delete the Azure resources you created so you don't incur more charges. 若要删除资源,请执行以下操作:To delete the resources:

  1. 在 Azure 门户的“搜索”栏中,搜索并选择“资源组” 。In the Azure portal Search bar, search for and select Resource groups.

  2. 从列表中选择为本快速入门创建的资源组。From the list, select the resource group you created for this quickstart.

    选择要删除的资源组

  3. 在资源组“概览”页上,选择“删除资源组” 。On the resource group Overview page, select Delete resource group.

    删除资源组

  4. 在下一窗口中输入要删除的资源组的名称,然后选择“删除” 。In the next window, enter the name of the resource group to delete, and then select Delete.

后续步骤Next steps

  • 了解如何将 Studio 3T 与 Azure Cosmos DB 的用于 MongoDB 的 API 配合使用。Learn how to use Studio 3T with Azure Cosmos DB's API for MongoDB.
  • 了解如何将 Robo 3T 与 Azure Cosmos DB 的用于 MongoDB 的 API 配合使用。Learn how to use Robo 3T with Azure Cosmos DB's API for MongoDB.
  • 通过 Azure Cosmos DB 的用于 MongoDB 的 API 来浏览 MongoDB 示例Explore MongoDB samples with Azure Cosmos DB's API for MongoDB.