表格存储提供了GetRow接口用于读取单行数据以及BatchGetRow、GetRange等接口用于读取多行数据。
查询方式
表格存储提供的数据读取接口包括GetRow、BatchGetRow和GetRange。读取数据时,请根据实际查询场景使用相应查询方式读取数据。
当要读取带有自增主键列的表数据时,请确保已获取到包含自增主键列值在内的完整主键。更多信息,请参见主键列自增。如果未记录自增主键列的值,您可以使用范围读取数据按照第一个主键列确定范围读取数据。
查询方式 | 说明 | 适用场景 |
调用GetRow接口读取一行数据。 | 适用于能确定完整主键且要读取行数较少的场景。 | |
调用BatchGetRow接口一次请求读取多行数据或者一次对多张表进行读取。 BatchGetRow操作由多个GetRow子操作组成,构造子操作的过程与使用GetRow接口时相同。 | 适用于能确定完整主键,且要读取行数较多或者要读取多个表中数据的场景。 | |
调用GetRange接口读取一个范围内的数据。 GetRange操作支持按照确定范围进行正序读取和逆序读取,可以设置要读取的行数。如果范围较大,已扫描的行数或者数据量超过一定限制,会停止扫描,并返回已获取的行和下一个主键信息。您可以根据返回的下一个主键信息,继续发起请求,获取范围内剩余的行。 | 适用于能确定完整主键范围或者主键前缀的场景。 重要 如果不能确定主键前缀,您也可以通过设置完整主键范围均为虚拟点INF_MIN和INF_MAX进行全表数据扫描,但是执行此操作会消耗较多计算资源,请谨慎使用。 |
前提条件
- 已初始化Client,详情请参见初始化。
- 已创建数据表并写入数据。
读取单行数据
调用GetRow接口读取一行数据。读取的结果可能有如下两种:
如果该行存在,则返回该行的各主键列以及属性列。
如果该行不存在,则返回中不包含行,并且不会报错。
接口
/*
* 根据给定的主键读取单行数据。
*/
getRow(params, callback)
参数
参数 | 说明 |
tableName | 数据表名称。 |
primaryKey | 行的主键。主键包括主键列名、主键类型和主键值。 重要 设置的主键个数和类型必须和数据表的主键个数和类型一致。 |
columnsToGet | 读取的列集合,列名可以是主键列或属性列。
说明
|
maxVersions | 最多读取的版本数。 重要 maxVersions与timeRange必须至少设置一个。
|
timeRange | 读取版本号范围或特定版本号的数据。更多信息,请参见TimeRange。 重要 maxVersions与timeRange必须至少设置一个。
specificTime和 时间戳的单位为毫秒,最小值为0,最大值为 |
columnFilter | 使用过滤器,在服务端对读取结果再进行一次过滤,只返回符合过滤器中条件的数据行。更多信息,请参见过滤器。 说明 当columnsToGet和columnFilter同时使用时,执行顺序是先获取columnsToGet指定的列,再在返回的列中进行条件过滤。 |
示例
读取一行数据。
var TableStore = require('../index.js');
var Long = TableStore.Long;
var client = require('./client');
var params = {
tableName: "sampleTable",
primaryKey: [{ 'gid': Long.fromNumber(20004) }, { 'uid': Long.fromNumber(20004) }],
maxVersions: 2 //最多可读取的版本数,设置为2即代表最多可读取2个版本。
};
var condition = new TableStore.CompositeCondition(TableStore.LogicalOperator.AND);
condition.addSubCondition(new TableStore.SingleColumnCondition('name', 'john', TableStore.ComparatorType.EQUAL));
condition.addSubCondition(new TableStore.SingleColumnCondition('addr', 'china', TableStore.ComparatorType.EQUAL));
params.columnFilter = condition;
client.getRow(params, function (err, data) {
if (err) {
console.log('error:', err);
return;
}
console.log('success:', data);
});
详细代码请参见GetRow@GitHub。
批量读取数据
调用BatchGetRow接口一次请求读取多行数据,也支持一次对多张表进行读取。BatchGetRow由多个GetRow子操作组成。构造子操作的过程与使用GetRow接口时相同。
BatchGetRow的各个子操作独立执行,表格存储会分别返回各个子操作的执行结果。
注意事项
由于批量读取可能存在部分行失败的情况,失败行的错误信息在返回的BatchGetRowResponse中,但并不抛出异常。因此调用BatchGetRow接口时,需要检查返回值,判断每行的状态是否成功。
批量读取的所有行采用相同的参数条件,例如
ColumnsToGet=[colA]
,表示要读取的所有行都只读取colA列。BatchGetRow操作单次支持读取的最大行数为100行。
接口
/**
* 批量读取一个或多个表中的若干行数据。
*/
batchGetRow(params, callback)
参数
BatchGetRow和GetRow的区别如下:
增加了数据表的层级结构,可以一次读取多个数据表的数据。
tables以数据表为单位组织,后续为各个数据表的操作,设置了需要读取的行信息。
primaryKey支持设置多行的主键,可以一次读取多行数据。
说明设置主键时,需要指定行数据的完整主键(包括主键名、主键类型和主键值),并确保对应主键在表中存在。如果表中不存在该主键,则返回结果中该主键对应行数据为空。
示例
批量一次读取多个数据表中的数据,并在出错时进行重试。
var client = require('./client');
var TableStore = require('../index.js');
var Long = TableStore.Long;
var params = {
tables: [{
tableName: 'sampleTable',
primaryKey: [
[{ 'gid': Long.fromNumber(20013) }, { 'uid': Long.fromNumber(20013) }],
[{ 'gid': Long.fromNumber(20015) }, { 'uid': Long.fromNumber(20015) }]
],
startColumn: "col2",
endColumn: "col4"
},
{
tableName: 'notExistTable',
primaryKey: [
[{ 'gid': Long.fromNumber(10001) }, { 'uid': Long.fromNumber(10001) }]
]
}
],
};
var maxRetryTimes = 3;
var retryCount = 0;
function batchGetRow(params) {
client.batchGetRow(params, function (err, data) {
if (err) {
console.log('error:', err);
return;
}
var isAllSuccess = true;
var retryRequest = { tables: [] };
for (var i = 0; i < data.tables.length; i++) {
var failedRequest = { tableName: data.tables[i][0].tableName, primaryKey: [] };
for (var j = 0; j < data.tables[i].length; j++) {
if (!data.tables[i][j].isOk && null != data.tables[i][j].primaryKey) {
isAllSuccess = false;
var pks = [];
for (var k in data.tables[i][j].primaryKey) {
var name = data.tables[i][j].primaryKey[k].name;
var value = data.tables[i][j].primaryKey[k].value;
var kp = {};
kp[name] = value;
pks.push(kp);
}
failedRequest.primaryKey.push(pks);
} else {
// get success data
}
}
if (failedRequest.primaryKey.length > 0) {
retryRequest.tables.push(failedRequest);
}
}
if (!isAllSuccess && retryCount++ < maxRetryTimes) {
batchGetRow(retryRequest);
}
console.log('success:', data);
});
}
batchGetRow(params, maxRetryTimes);
详细代码请参见BatchGetRow@GitHub。
范围读取数据
调用GetRange接口读取一个范围内的数据。
GetRange操作支持按照确定范围进行正序读取和逆序读取,可以设置要读取的行数。如果范围较大,已扫描的行数或者数据量超过一定限制,会停止扫描,并返回已获取的行和下一个主键信息。您可以根据返回的下一个主键信息,继续发起请求,获取范围内剩余的行。
表格存储表中的行都是按照主键排序的,而主键是由全部主键列按照顺序组成的,所以不能理解为表格存储会按照某列主键排序,这是常见的误区。
注意事项
GetRange操作遵循最左匹配原则,读取数据时,依次比较第一主键列到第四主键列。例如表的主键包括PK1、PK2、PK3三个主键列,读取数据时,优先比较PK1是否在开始主键与结束主键的范围内,如果PK1在设置的主键范围内,则不会再比较其他的主键,返回在PK1主键范围内的数据;如果PK1在设置的主键边界上,则继续比较PK2是否在开始主键与结束主键的范围内,以此类推。
GetRange操作可能在如下情况停止执行并返回数据。
扫描的行数据大小之和达到4 MB。
扫描的行数等于5000。
返回的行数等于最大返回行数。
当前剩余的预留读吞吐量已全部使用,余量不足以读取下一条数据。
当使用GetRange扫描的数据量较大时,表格存储每次请求仅会扫描一次(行数大于5000或者大小大于4 MB停止扫描),超过限制的数据不会继续返回,需要通过翻页继续获取后面的数据。
接口
/**
* 读取指定主键范围内的数据。
*/
getRange(params, callback)
参数
参数 | 说明 |
tableName | 数据表名称。 |
direction | 读取方向。
假设同一表中有两个主键A和B,A小于B,如果正序读取 |
inclusiveStartPrimaryKey | 本次范围读的起始主键和结束主键,起始主键和结束主键需要是有效的主键或者是由INF_MIN和INF_MAX类型组成的虚拟点,虚拟点的列数必须与主键相同。 其中INF_MIN表示无限小,任何类型的值都比它大;INF_MAX表示无限大,任何类型的值都比它小。
数据表中的行按主键从小到大排序,读取范围是一个左闭右开的区间,正序读取时,返回的是大于等于起始主键且小于结束主键的所有的行。 |
exclusiveEndPrimaryKey | |
limit | 数据的最大返回行数,此值必须大于0。 表格存储按照正序或者逆序返回指定的最大返回行数后即结束该操作的执行,即使该区间内仍有未返回的数据。此时可以通过返回结果中的nextStartPrimaryKey记录本次读取到的位置,用于下一次读取。 |
columnsToGet | 读取的列集合,列名可以是主键列或属性列。
说明
|
maxVersions | 最多读取的版本数。 重要 maxVersions与timeRange必须至少设置一个。
|
timeRange | 读取版本号范围或特定版本号的数据。更多信息,请参见TimeRange。 重要 maxVersions与timeRange必须至少设置一个。
specificTime和 时间戳的单位为毫秒,最小值为0,最大值为 |
columnFilter | 使用过滤器,在服务端对读取结果再进行一次过滤,只返回符合过滤器中条件的数据行。更多信息,请参见过滤器。 说明 当columnsToGet和columnFilter同时使用时,执行顺序是先获取columnsToGet指定的列,再在返回的列中进行条件过滤。 |
nextStartPrimaryKey | 根据返回结果中的nextStartPrimaryKey判断数据是否全部读取。
|
示例
按照范围读取数据。
var Long = TableStore.Long;
var client = require('./client');
var params = {
tableName: "sampleTable",
direction: TableStore.Direction.FORWARD,
inclusiveStartPrimaryKey: [{ "gid": TableStore.INF_MIN }, { "uid": TableStore.INF_MIN }],
exclusiveEndPrimaryKey: [{ "gid": TableStore.INF_MAX }, { "uid": TableStore.INF_MAX }],
limit: 50
};
client.getRange(params, function (err, data) {
if (err) {
console.log('error:', err);
return;
}
//如果data.next_start_primary_key不为空,则继续读取。
if (data.next_start_primary_key) {
}
console.log('success:', data);
});
详细代码请参见GetRange@GitHub。