带动态键的JSON字段索引

时间:2016-10-20 15:25:53

标签: postgresql indexing

我在PG 9.5上,我有一张桌子Visitor(id: 1, data: {name: 'Jack', age: 33, is_user: true })

示例:

    $scope.checkwind = function(){
                if (!$scope.popupWindow) {
                     $scope.windowstatus = "Window hasn't opened yet";

} else {
if ($scope.popupWindow.closed) {

         $scope.windowstatus = "Window is Currently Closed"
        } 
        else {

         $scope.windowstatus = "Window is Currently Open";
    } 
}
console.log($scope.windowstatus);
}
$interval( function(){ $scope.checkwind(); }, 100);

我想执行像

这样的查询
  • 给我所有名为杰克和年龄的访客> 25
  • 向我提供所有用户的访问者,但名称未指定的地方(密钥不在json中)

用户指定的数据列中的键是动态的。

在这种情况下哪个指数最有意义?

3 个答案:

答案 0 :(得分:4)

您可以在GIN index上使用jsonb column,它可以为JSON值中的键和值提供广义的动态索引。

CREATE TABLE visitors (
  id integer,
  data jsonb
);

CREATE INDEX idx_visitors_data ON cards USING GIN (data);

SELECT * FROM visitors
WHERE data -> 'is_user' AND NOT data ? 'name';

不幸的是,GIN索引不支持数值范围比较。因此,您仍然可以为年龄超过25岁的名为Jack的访问者发出查询:

SELECT * FROM visitors
WHERE data @> '{"name": "Jack"}' AND ((data ->> 'age')::integer) > 25;

这将仅使用索引来查找名称" Jack",并且可能找到具有" age"的行。键,但年龄超过25的实际测试将作为对匹配行的扫描完成。

请注意,如果您确实需要范围比较,您仍然可以在JSON值内的特定路径上添加非GIN索引,如果您希望它们经常出现以使其值得。例如,您可以在data -> 'age'上添加支持范围比较的索引:

CREATE INDEX idx_visitors_data_age ON visitors ( ((data ->> 'age')::integer) );

(注意额外的括号;如果没有它们,你会收到错误)。

有关详细信息,请参阅this excellent blog post

答案 1 :(得分:0)

你可以查看额外的扩展JsQuery - 是一种查询jsonb数据类型的语言,它为jsonb提供了一个附加功能(目前在PostgreSQL中缺失),比如在嵌套对象和数组中搜索的简单有效方法,更多具有索引支持的比较运算符在此处阅读更多内容:https://github.com/postgrespro/jsquery

在您的情况下,您可以创建jsonb_path_value_ops索引:

CREATE INDEX idx_visitors ON visitors USING GIN (jsonb jsonb_path_value_ops);

并使用下一个查询:

select * from visitors where jsonb @@ 'name = "Jack" and age > 25';
select * from visitors where jsonb @@ 'not name = * and is_user=true';

答案 2 :(得分:0)

我相信这里最好的方法是创建原始sql迁移:

  1. 运行./manage.py makemigrations --empty yourApp,其中yourApp是您要为其更改索引的模型的应用程序。

  2. 即编辑迁移

operations = [
    migrations.RunSQL("CREATE INDEX idx_content_taxonomies_categories ON common_content((taxonomies->>'categories'));")
]

其中idx_content_taxonomies_categories是索引的名称,common_content是您的表,taxonomies是您的JSONField,在这种情况下,categories是您要索引的键

应该这样做。干杯!