如何在对象数组上查询 RethinkDB 中的多索引
How to query a multi index in RethinkDB over an array of objects
我正在处理一个看起来像这样的数据集:
"bitrates": [
{
"format": "mp3" ,
"rate": "128K"
} ,
{
"format": "aac" ,
"rate": "192K"
}
] ,
"details": [ ... ] ,
"id": 1 ,
"name": "For Those About To Rock We Salute You" ,
"price": 1026 ,
"requires_shipping": false ,
"sku": "ALBUM-1"
}
我想在 bitrates
上创建一个二级索引,flexing {multi:true}
。这是我的尝试:
r.db("music").table("catalog").indexCreate("bitrates", {multi: true})
索引建立得很好,但是当我查询它时,什么也没有 returns - 这似乎与我在这里读到的每个例子都相反:
http://rethinkdb.com/docs/secondary-indexes/javascript/
我写的查询是这样的:
r.db("music").table("catalog").getAll(["mp3", "128K"], {index : "bitrates"})
没有错误,只有 0 个结果(我有 300 份左右的文件包含这个确切的数据)。
我正在使用 RethinkDB 2.0 RC1。
当您为列创建索引时,列中的值按字面意义用作索引的键。在您的情况下,bitrates
索引的键将是文档中 bitrates
数组中的对象。
您似乎想要的是一个从文档字段中的值派生的索引。为此,您需要定义一个自定义索引函数,将文档缩减为仅包含您关心的数据。试验它们的最简单方法是从编写查询开始,一旦您对结果感到满意,就将其转换为 indexCreate()
语句。
这是一个获取示例文档(ID 为 1)的语句,并从其 bitrate
数组中的所有对象中提取 format
和 rate
术语,然后将它们合并在一起以创建一组不同的字符串:
r.db('music').table('catalog').get(1).do(function(row) {
return row('bitrates').map(function(bitrate) {
return [bitrate('format'), bitrate('rate')];
}).reduce(function(left, right) {
return left.setUnion(right);
})
})
运行 此语句将 return 以下内容:
["mp3", "128K", "aac", "192K"]
这看起来不错,所以我们可以使用我们的函数来创建索引。在这种情况下,由于我们期望索引函数 return 一组项目,我们还想指定 {multi: true}
以确保我们可以通过 items 在集合中,而不是集合本身:
r.db('music').table('catalog').indexCreate('bitrates', function(row) {
return row('bitrates').map(function(bitrate) {
return [bitrate('format'), bitrate('rate')];
}).reduce(function(left, right) {
return left.setUnion(right);
})
}, {multi: true})
创建后,您可以像这样查询您的索引:
r.db('music').table('catalog').getAll('mp3', {index: 'bitrates'})
您还可以提供多个查询词,以匹配匹配任何项目的行:
r.db('music').table('catalog').getAll('mp3', '128K', {index: 'bitrates'})
但是,如果单个文档与您的查询中的多个字词匹配,它将被 return 编辑多次。要解决此问题,请添加 distinct()
:
r.db('music').table('catalog').getAll('mp3', '128K', {index: 'bitrates'}).distinct()
如有必要,您也可以考虑使用 downcase()
规范二级索引中使用的术语的大小写。
您也可以完全跳过所有索引业务并使用 filter()
查询:
r.db('music').table('catalog').filter(function(row) {
return row('bitrates').map(function(bitrates) {
return [bitrates('format'), bitrates('rate')];
}).reduce(function(left, right) {
return left.setUnion(right);
}).contains('mp3');
})
也就是说,如果您几乎总是以相同的方式查询 table,则使用自定义函数生成二级索引会显着提高性能。
二级索引的键现在不能是对象:
> r.table('foo').indexCreate('bitrates', {multi: true})
> r.table('foo').getAll({format: "mp3", rate: "128K"}, {index: 'bitrates'})
RqlRuntimeError: Secondary keys must be a number, string, bool, pseudotype, or array
您可以在 https://github.com/rethinkdb/rethinkdb/issues/2773 跟踪此问题。
要解决这个问题,您可以这样做:
> r.table('foo').indexCreate('bitrates', function(row){
return row('bitrates').map(function(bitrate){return bitrate.coerceTo('array');})
}, {multi: true});
> r.table('foo').getAll(r.expr({format: "mp3", rate: "128K"}).coerceTo('array'), {index: 'bitrates'})
我正在处理一个看起来像这样的数据集:
"bitrates": [
{
"format": "mp3" ,
"rate": "128K"
} ,
{
"format": "aac" ,
"rate": "192K"
}
] ,
"details": [ ... ] ,
"id": 1 ,
"name": "For Those About To Rock We Salute You" ,
"price": 1026 ,
"requires_shipping": false ,
"sku": "ALBUM-1"
}
我想在 bitrates
上创建一个二级索引,flexing {multi:true}
。这是我的尝试:
r.db("music").table("catalog").indexCreate("bitrates", {multi: true})
索引建立得很好,但是当我查询它时,什么也没有 returns - 这似乎与我在这里读到的每个例子都相反:
http://rethinkdb.com/docs/secondary-indexes/javascript/
我写的查询是这样的:
r.db("music").table("catalog").getAll(["mp3", "128K"], {index : "bitrates"})
没有错误,只有 0 个结果(我有 300 份左右的文件包含这个确切的数据)。
我正在使用 RethinkDB 2.0 RC1。
当您为列创建索引时,列中的值按字面意义用作索引的键。在您的情况下,bitrates
索引的键将是文档中 bitrates
数组中的对象。
您似乎想要的是一个从文档字段中的值派生的索引。为此,您需要定义一个自定义索引函数,将文档缩减为仅包含您关心的数据。试验它们的最简单方法是从编写查询开始,一旦您对结果感到满意,就将其转换为 indexCreate()
语句。
这是一个获取示例文档(ID 为 1)的语句,并从其 bitrate
数组中的所有对象中提取 format
和 rate
术语,然后将它们合并在一起以创建一组不同的字符串:
r.db('music').table('catalog').get(1).do(function(row) {
return row('bitrates').map(function(bitrate) {
return [bitrate('format'), bitrate('rate')];
}).reduce(function(left, right) {
return left.setUnion(right);
})
})
运行 此语句将 return 以下内容:
["mp3", "128K", "aac", "192K"]
这看起来不错,所以我们可以使用我们的函数来创建索引。在这种情况下,由于我们期望索引函数 return 一组项目,我们还想指定 {multi: true}
以确保我们可以通过 items 在集合中,而不是集合本身:
r.db('music').table('catalog').indexCreate('bitrates', function(row) {
return row('bitrates').map(function(bitrate) {
return [bitrate('format'), bitrate('rate')];
}).reduce(function(left, right) {
return left.setUnion(right);
})
}, {multi: true})
创建后,您可以像这样查询您的索引:
r.db('music').table('catalog').getAll('mp3', {index: 'bitrates'})
您还可以提供多个查询词,以匹配匹配任何项目的行:
r.db('music').table('catalog').getAll('mp3', '128K', {index: 'bitrates'})
但是,如果单个文档与您的查询中的多个字词匹配,它将被 return 编辑多次。要解决此问题,请添加 distinct()
:
r.db('music').table('catalog').getAll('mp3', '128K', {index: 'bitrates'}).distinct()
如有必要,您也可以考虑使用 downcase()
规范二级索引中使用的术语的大小写。
您也可以完全跳过所有索引业务并使用 filter()
查询:
r.db('music').table('catalog').filter(function(row) {
return row('bitrates').map(function(bitrates) {
return [bitrates('format'), bitrates('rate')];
}).reduce(function(left, right) {
return left.setUnion(right);
}).contains('mp3');
})
也就是说,如果您几乎总是以相同的方式查询 table,则使用自定义函数生成二级索引会显着提高性能。
二级索引的键现在不能是对象:
> r.table('foo').indexCreate('bitrates', {multi: true})
> r.table('foo').getAll({format: "mp3", rate: "128K"}, {index: 'bitrates'})
RqlRuntimeError: Secondary keys must be a number, string, bool, pseudotype, or array
您可以在 https://github.com/rethinkdb/rethinkdb/issues/2773 跟踪此问题。
要解决这个问题,您可以这样做:
> r.table('foo').indexCreate('bitrates', function(row){
return row('bitrates').map(function(bitrate){return bitrate.coerceTo('array');})
}, {multi: true});
> r.table('foo').getAll(r.expr({format: "mp3", rate: "128K"}).coerceTo('array'), {index: 'bitrates'})