宇宙数据库和节点软件开发工具包第1部分:使用数据库


在过去的几年里,我学到了很多东西,我想分享我学到的东西,但是有一件事让我无法参与。我希望我能打破这种沉默,定期发表文章。

继续我的工作Cerebrata Cerulean,我有机会与Node.js和一些令人惊叹的Azure服务一起工作。在这一系列帖子中,我将重点关注使用Azure Cosmos DB用他们的节点软件开发工具包服务。我们将涵盖与各种实体的合作,如数据库、容器(集合)、文档等。使用节点软件开发工具包。

在这篇文章中,我们将重点关注数据库。我们将看到如何在数据库上执行各种操作,如列表、创建、删除等。

开始之前

在我们开始之前,您需要做一些事情:

  • 宇宙数据库帐户凭证:你需要一个宇宙数据库帐户(帐户名称和密钥)。此帐户应该以SQL应用编程接口为目标。
  • 为宇宙数据库安装节点软件开发工具包:有关为宇宙数据库安装节点软件开发工具包的更多信息,请访问https://www.npmjs.com/package/@azure/cosmos。在写这篇文章的时候,软件开发工具包的最新版本是2.1.5,所以我们将只使用它。
  • 安装蓝鸟:我们将展示使用异步/等待以及承诺的代码。对于承诺,我们将使用蓝鸟图书馆。你可以在以下网址找到更多关于这个图书馆的信息https://www.npmjs.com/package/bluebird

假设您已经创建了一个文件夹并安装了软件包,让我们创建一个名为“database-samples.js”的文件,并在其中添加以下代码行:

const {Promise} = require('bluebird');
const {CosmosClient, Database} = require('@azure/cosmos');

const accountEndpoint = 'https://account-name.documents.azure.com:443/';
const accountKey = 'yM0g3KnPANPpBgKLi34OMz1UZ7Png2pjQrs209IrrQkyhtqZKmALludel1nizEOqeJMm1gavLb0dS0gAoMw3Pw==';

/**
** Method to get client connection object.
**/
const getClient = () => {
   return new CosmosClient({
     endpoint: accountEndpoint,
     auth: {
       masterKey: accountKey
     }
   });
 };

请确保使用您的宇宙数据库帐户凭证的值。

我们现在都准备好前进了!

还有一件事。因为我们将包含异步/等待和承诺的代码,所以我们将在方法名称前面加上我们正在使用的方法。例如,“列表数据库同步”和“列表数据库同步”分别表示异步/等待和承诺。

列出数据库

假设我们想要列出一个帐户中的所有数据库。我们将这样做。

使用异步/等待

下面是使用异步/等待列出数据库的代码:

const listDatabasesAsync = async () => {
  const client = getClient();
  const iterator = await client.databases.readAll().toArray();
  const databases = [];
  iterator.result.forEach((item) => {
    databases.push(item);
  });
  return databases;
};

我们在这里做的第一件事是获取CosmosClient然后使用类中的方法读取所有数据库。这个方法的输出将是一个数组,看起来如下所示:

[ 
    { 
        id: 'database-000',//name of the database
        _rid: 'xD4MAA==',//system assigned id to the database
        _self: 'dbs/xD4MAA==/',//self link
        _etag: '"00004d00-0000-0100-0000-5cf55d1d0000"',//etag
        _colls: 'colls/',
        _users: 'users/',
        _ts: 1559584029 //timestamp (in unix epoch)
    },
    {   id: 'database-001',
        _rid: 'B+kiAA==',
        _self: 'dbs/B+kiAA==/',
        _etag: '"00004e00-0000-0100-0000-5cf55d230000"',
        _colls: 'colls/',
        _users: 'users/',
        _ts: 1559584035 
    } 
]

使用承诺

下面是使用promise列出数据库的代码:

const listDatabasesPromise = () => {
  return new Promise((resolve, reject) => {
    const client = getClient();
    client.databases.readAll().toArray()
    .then((databasesListingResult) => {
      const databases = [];
      databasesListingResult.result.forEach((item) => {
        databases.push(item);
      });
      resolve(databases);
    })
    .catch((error) => {
      reject(error);
    });
  });
}

创建数据库

接下来,让我们看看如何在宇宙数据库帐户中创建一个数据库。假设我们想创建一个名为“awesomedb”的数据库。

使用异步/等待

下面是使用异步/等待创建数据库的代码:

const createDatabaseAsync = async (databaseId) => {
  const databaseDefinition = {
    id: databaseId
  };
  const client = getClient();
  const result = await client.databases.create(databaseDefinition);
  return result;
};

//This is how you would call it.
const runAsync = async () => {
  let databaseName = 'awesomedb';
  console.log(`creating database: ${databaseName}`);
  const result = await createDatabaseAsync(databaseName);
  console.log(result);
};

runAsync().catch((error) => {
  console.log(error);
});

我们在这里做的是首先得到一个CosmosClient然后在类中调用方法。

此方法的输出是一个具有以下关键成员的对象:

  • 正文:包含数据库的系统属性,如_rid、_self、_etag、_ts等。
  • 标题:这包含响应标题。
  • 数据库:这实际上是类的一个实例。如果您想对数据库执行任何操作,如读取其属性、删除等,您将需要使用这个对象。

请注意,如果帐户中已经存在同名的数据库,上述方法将会失败

要解决这个问题,我们只需使用createIfNotExists方法。就这么简单!下面是这样做的代码:

const createDatabaseIfNotExistsAsync = async (databaseId) => {
  const databaseDefinition = {
    id: databaseId
  };
  const client = getClient();
  const result = await client.databases.createIfNotExists(databaseDefinition);
  return result;
};

使用承诺

如果你要使用承诺,下面是代码:

const createDatabasePromise = (databaseId) => {
  return new Promise((resolve, reject) => {
    const databaseDefinition = {
      id: databaseId
    };
    const client = getClient();
    client.databases.create(databaseDefinition)
    .then((result) => {
      resolve(result);
    })
    .catch((error) => {
      reject(error);
    });
  });
};

const createDatabaseIfNotExistsPromise = (databaseId) => {
  return new Promise((resolve, reject) => {
    const databaseDefinition = {
      id: databaseId
    };
    const client = getClient();
    client.databases.createIfNotExists(databaseDefinition)
    .then((result) => {
      resolve(result);
    })
    .catch((error) => {
      reject(error);
    });
  });
};

创建具有预配吞吐量的数据库

默认情况下,当您创建一个数据库时,它没有自己的吞吐量。该数据库中的每个容器都有自己的吞吐量,这是您在创建该容器时定义的。

但是,您想要做的是在数据库级别定义吞吐量,以便所有容器共享该吞吐量。如果你来自于SQL数据库世界,这有点类似于弹性数据库池(尽管相似性仅在概念层面;这里有一些显著的不同,但这超出了本文的范围。

因此,假设我们想要创建一个名为“awesomedb”的数据库,提供1000 RU/s的吞吐量。

使用异步/等待

下面是使用异步/等待创建具有预配吞吐量的数据库的代码:

const createDatabaseWithProvisionedThroughputAsync = async (databaseId, throughput) => {
  const databaseDefinition = {
    id: databaseId
  };
  const requestOptions = {
    offerThroughput: throughput
  };
  const client = getClient();
  const result = await client.databases.create(databaseDefinition, requestOptions);
  return result;
};

//This is how you would call it.
const runAsync = async () => {
  let databaseName = 'awesomedb';
  console.log(`creating database: ${databaseName}`);
  const result = await createDatabaseWithProvisionedThroughputAsync(databaseName, 1000);
  console.log(result);
};

runAsync().catch((error) => {
  console.log(error);
});
const createDatabaseIfNotExistsWithProvisionedThroughputAsync = async (databaseId, throughput) => {
  const databaseDefinition = {
    id: databaseId
  };
  const requestOptions = {
    offerThroughput: throughput
  };
  const client = getClient();
  const result = await client.databases.createIfNotExists(databaseDefinition, requestOptions);
  return result;
};

//This is how you would call it.
const runAsync = async () => {
  let databaseName = 'awesomedb';
  console.log(`creating database: ${databaseName}`);
  const result = await createDatabaseWithProvisionedThroughputAsync(databaseName, 1000);
  console.log(result);
};

runAsync().catch((error) => {
  console.log(error);
});

如果您查看上面的代码,您会注意到它非常类似于我们用来创建没有提供吞吐量的数据库的代码。要创建具有预配吞吐量的数据库,我们只需定义一个requestOption对象,并将我们想要的吞吐量指定为offerThroughput财产。真的就这么简单!

请注意,在写这篇文章的时候,一个数据库可以拥有的最小吞吐量是400 RU/s,您可以通过编程设置的最大吞吐量是100000 RU/s。对于超过这个限制的吞吐量,您需要调用Azure支持。

使用承诺

如果你要使用承诺,下面是代码:

const createDatabaseWithProvisionedThroughputPromise = (databaseId, throughput) => {
  return new Promise((resolve, reject) => {
    const databaseDefinition = {
      id: databaseId
    };
    const requestOptions = {
      offerThroughput: throughput
    };
    const client = getClient();
    client.databases.create(databaseDefinition, requestOptions)
    .then((result) => {
      resolve(result);
    })
    .catch((error) => {
      reject(error);
    })
  });
};

const createDatabaseIfNotExistsWithProvisionedThroughputPromise = (databaseId, throughput) => {
  return new Promise((resolve, reject) => {
    const databaseDefinition = {
      id: databaseId
    };
    const requestOptions = {
      offerThroughput: throughput
    };
    const client = getClient();
    client.databases.createIfNotExists(databaseDefinition, requestOptions)
    .then((result) => {
      resolve(result);
    })
    .catch((error) => {
      reject(error);
    });
  });
};

获取数据库属性

接下来,让我们看看如何读取数据库的属性。

使用异步/等待

下面是使用异步/等待获得具有预配吞吐量的数据库属性的代码:

const getDatabasePropertiesAsync = async (databaseId) => {
  const client = getClient();
  const db = client.database(databaseId);
  const result = await db.read();
  return result;
}

代码非常简单。首先,我们得到一个CosmosClient然后获取类的一个实例,然后我们调用该对象上的方法。

此方法的输出是一个具有以下关键成员的对象:

  • 正文:包含数据库的系统属性,如_rid、_self、_etag、_ts等。
  • 标题:这包含响应标题。
  • 数据库:这实际上是类的一个实例。

使用承诺

如果你要使用承诺,下面是代码:

const getDatabasePropertiesPromise = (databaseId) => {
  return new Promise((resolve, reject) => {
    const client = getClient();
    const db = client.database(databaseId);
    db.read()
    .then((result) => {
      resolve(result);
    })
    .catch((error) => {
      reject(error);
    });
  });
};

删除数据库

接下来,让我们看看如何删除数据库。

使用异步/等待

下面是使用异步/等待删除数据库的代码:

const deleteDatabaseAsync = async (databaseId) => {
  const client = getClient();
  const db = client.database(databaseId);
  await db.delete();
  return true;
};

同样,代码非常简单。首先,我们得到一个CosmosClient然后得到一个类的实例,然后我们调用这个对象上的方法。

我唯一的愿望是软件开发工具包引入一个功能,比如deleteIfExists,类似于createIfNotExists

使用承诺

如果你要使用承诺,下面是代码:

const deleteDatabasePromise = (databaseId) => {
  return new Promise((resolve, reject) => {
    const client = getClient();
    const db = client.database(databaseId);
    db.delete()
    .then((result) => {
      resolve(true);
    })
    .catch((error) => {
      reject(error);
    });
  });
};

获取数据库吞吐量

假设我们创建了一个具有调配吞吐量的数据库,我们想知道该吞吐量是多少。

考虑到我们定义了数据库的吞吐量,我们希望数据库的一个属性能告诉我们这一点,但事实并非如此:)。

要获得数据库(或容器)的吞吐量,实际上需要使用应用编程接口。让我们看看这是如何工作的。

使用异步/等待

下面是使用异步/等待获得数据库报价的代码:

const getDatabaseOfferAsync = async (databaseId) => {
  const client = getClient();
  const db = client.database(databaseId);
  const {body: databaseProperties} = await db.read();
  const selfLink = databaseProperties._self;
  const querySpec = {
    query: 'SELECT * FROM root r WHERE  r.resource = @link',
    parameters: [{
        name: '@link',
        value: selfLink
    }]
  };
  const offerListingResult = await client.offers.query(querySpec).toArray();
  const offer = offerListingResult.result[0];
  return offer;
};

为了获得资源的报价(在本例中是数据库),我们需要selfLink资源属性。这就是我们在上面的代码中所做的。

首先,我们得到一个CosmosClient。接下来,我们创建一个实例Database并读取数据库属性,这样我们就可以访问_self数据库属性。然后,我们调用类中的方法来获取数据库中可用的报价。

输出如下所示:

{ 
    resource: 'dbs/dEwOAA==/',
    offerType: 'Invalid',
    offerResourceId: 'dEwOAA==',
    offerVersion: 'V2',
    content:
    { 
        offerThroughput: 400,
        offerIsRUPerMinuteThroughputEnabled: false 
    },
    id: 'BlZx',
    _rid: 'BlZx',
    _self: 'offers/BlZx/',
    _etag: '"00005200-0000-0100-0000-5cf5ee200000"',
    _ts: 1559621152 
}

要获得吞吐量,只需阅读offerThroughtput的属性content结果的属性。

使用承诺

如果你要使用承诺,下面是代码:

const getDatabaseOfferPromise = (databaseId) => {
  return new Promise((resolve, reject) => {
    const client = getClient();
    const db = client.database(databaseId);
    db.read()
    .then((result) => {
      const databaseProperties = result.body;
      const selfLink = databaseProperties._self;
      const querySpec = {
        query: 'SELECT * FROM root r WHERE  r.resource = @link',
        parameters: [{
            name: '@link',
            value: selfLink
        }]
      };
      client.offers.query(querySpec).toArray()
      .then((offerListingResult) => {
        const offer = offerListingResult.result[0];
        resolve(offer);
      })
      .catch((error) => {
        reject(error);
      });
    })
    .catch((error) => {
      reject(error);
    });
  });
};

更新数据库吞吐量

这是我们为这篇文章做的最后一件事。假设您创建了一个具有一些预配吞吐量的数据库,现在您想要更改该吞吐量。

实现这一点的方法是获取数据库的报价,更新offerThroughtput属性,然后用修改后的要约替换现有要约。

使用异步/等待

下面是使用异步/等待更新数据库报价的代码:

const updateDatabaseProvisionedThroughputAsync = async (databaseId, provisionedThroughput) => {
  const offerDetails = await getDatabaseOfferAsync(databaseId);
  offerDetails.content.offerThroughput = provisionedThroughput;
  const client = getClient();
  const offer = client.offer(offerDetails.id);
  await offer.replace(offerDetails);
};

代码非常简单。首先,我们通过我们的getDatabaseOfferAsync方法。然后,我们将更新该产品中提供的吞吐量。

接下来,我们得到一个CosmosClient。使用它和报价id,我们创建一个类的实例,最后调用该类上的方法来替换报价。

使用承诺

如果你要使用承诺,下面是代码:

const updateDatabaseProvisionedThroughputPromise = (databaseId, provisionedThroughput) => {
  return new Promise((resolve, reject) => {
    getDatabaseOfferPromise(databaseId)
    .then((offerDetails) => {
      offerDetails.content.offerThroughput = provisionedThroughput;
      const client = getClient();
      const offer = client.offer(offerDetails.id);
      offer.replace(offerDetails)
      .then((result) => {
        resolve(result);
      })
      .catch((error) => {
        reject(error);
      });
    })
    .catch((error) => {
      reject(error);
    });
  });
};

包扎

这篇文章到此为止!在下一系列文章中,我们将对容器(集合)、文档和其他东西做同样的事情,所以请继续关注。

如果您在这篇文章中发现代码样本或任何其他信息有任何问题,请让我知道,我会尽快解决它们。

快乐编码!