简体   繁体   中英

How to improve or index postgresql's jsonb array field?

I usually use jsonb field store array data. for example, I want to store customer's barcode info, I will create a table like this:

create table customers(fcustomerid bigint, fcodes jsonb);

One customer has one row, all barcode info stored in its fcodes field, just like below:

[
{
    "barcode":"000000001",
    "codeid":1,
    "product":"Coca Cola",
    "createdate":"2021-01-19",
    "lottorry":true,
    "lottdate":"2021-01-20",
    "bonus":50
},
{
    "barcode":"000000002",
    "codeid":2,
    "product":"Coca Cola",
    "createdate":"2021-01-19",
    "lottorry":false,
    "lottdate":"",
    "bonus":0
}
...
{
    "barcode":"000500000",
    "codeid":500000,
    "product":"Pepsi Cola",
    "createdate":"2021-01-19",
    "lottorry":false,
    "lottdate":"",
    "bonus":0
}
]

The jsonb array maybe store millions of barcode's objects with the same structure. Perhaps this is not a good idea, but you konw when I have thousands of customer, I can store all the data in one table, one customer has one row in this table, all its data store in one field, it looks very tersely and easy to manage.

For this kind of application scenarios, how to efficiently to insert or modify or query the data?

I can use jsonb_insert to insert one object, just like:

update customers 
set fcodes=jsonb_insert(fcodes,'{-1}','{...}'::jsonb) 
where fcustomerid=999;

When I want modify some object, I found it is a little difficulty, I should know the index of object first, if I use the incremental key codeid as the array index, things looks easilly. I can use jsonb_modify ,Just like below:

update customers 
set fcodes=jsonb_set(fcodes,concat('{',(mycodeid-1)::text,',lottery}'),'true'::jsonb) 
where fcustomerid=999;

But if I want to query the objects in the jsonb array with createdate or bonus or lottorry or product , I should use jsonpath operator. just like:

select jsonb_path_query_array(fcodes,'$ ? (product=="Pepsi Cola")' 
from customer 
where fcustomerid=999;

or like:

select jsonb_path_query_array(fcodes,'$ ? (lottdate.datetime()>="2021-01-01".datetime() && lottdate.datetime()<="2021-01-31".datetime())' 
from customer 
where fcustomerid=999;

Thie jsonb index looks useful, But it looks useful between different row, and my operation mostly works in one row's one jsonb field.

I am very worrying about the efficiency, for millions of objects stored in one row's one jsonb field, is this a good idea? And how to improve the efficiency in this scenarios? Especially for the query.

You are right to worry. With a huge JSON like that, you will never get good performance.

Your data don't need JSON at all. Create a table that stores a single barcode and has a foreign key reference to customers . Then everything will be simple and efficient.

Using JSON in the database is almost always the wrong choice, judging from the questions in this forum.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM