Postgresql JSONB object column to Array - postgresql

I am working with an existing table, where the column is of type JSONB. The data looks like this:
{ key1: {...}, key2: {...}}
I would like to migrate all the existing data in this DB so that this JSONB data looks like this instead:
[{ key1: {...}, key2: {...}}]
I want the existing object to be wrapped in an array.
I think I might be able to use jsonb_build_array, but I'm not completely sure.
Has anyone had to do this before?

Yes, jsonb_build_array() is the right approach:
update the_table
set the_column = jsonb_build_array(the_column);

Related

How to push to an array inside of a JSON object in a JSONB column in PostgreSQL

I have the below data in a JSONB column in PostgreSQL.
{
"myFirstDeck" : {
"cards": [1, 2, 3]
}
}
I would like to use one of the inbuilt JSONB PostgreSQL functions to push/append an integer to the cards array inside of the myFirstDeck key/object.
Any assistance would be much appreciated.
I have tried various variations using jsonb_set and concatenation but am struggling to get it working.
You can use jsonb_insert()
The following appends the value 4 at the end of the array
jsonb_insert(the_column, '{myFirstDeck,cards,-1}', to_jsonb(4), true)
But if you find yourself doing this a lot you should seriously consider using a properly normalized data model rather than abusing JSON.

How to use dot notation in Cloud Firestore to query nested properties in a list of maps

So I have a collection of documents in cloud firestore where each document has this structure:
{
key1: value1
key2: value2
access: [{key: {key: value, key: value}, users: [...keys]},]
}
From a widget I want to get the documents where the id that I have exists in the users array. My query is this: labs.where('access.users', arrayContains: user.id).get()
I have read that in order to query nested elements you need dot notation. My problem is that it results in an error -> Bad state: No element. Which I assume is, because firestore doesn't know which access.users to query on since it is a list, but on the other hand I imagine that it should take each map one by one.
Maybe I'm missing something in my logic. Help is appreciated.
As Dharmaraj commented, the arrayContains operator checks whether the array contains an item that is exactly the same as you pass to it. There is no way to pass a partial object to arrayContains and check for the presence of just that part.
The common workaround is to create an additional array field that just contains the values you also want to query on. So in your case that'd be an array of the UIDs that have access:
access_users: ["uid1", "uid2", "uid3"]
And then your query would become:
labs.where('access_users', arrayContains: user.id).get()

postgres parse json to find compatible entries

I am new to PostgreSQL I created a table with a JSON type column
id,country_code
11767,{"country_code": [{"code": "GB01F290/00", "new": 1}, {"code": "DE08F290/00", "new": 1}, {"code": "GB02F290/00", "new": 1}]}
11768,{"country_code": [{"code": "GB01F290/20", "new": 1}, {"code": "GB20F290/23", "new": 1}]}
list = ["GB01F290/00", "GB21F290/41"]
How can I select the rows that country_code:code contains any element of the list?
There is probably a way to create a jsonpath query to do this, but you would need some way to transform your ["GB01F290/00", "GB21F290/41"] into the correct jsonpath. I'm not very good at jsonpath, so I won't go into that.
Another way to do this would be to use the #> operator with the ANY(...) construct. But that takes a PostgreSQL array of jsonb documents as its right-hand-side, and each document needs to have a specific structure to match the structure of the documents you are querying. One way to express that array of jsonb would be:
'{"{\"country_code\": [{\"code\": \"GB01F290/00\"}]}","{\"country_code\": [{\"code\": \"GB21F290/41\"}]}"}'::jsonb[]
Or another way, with less obnoxious quoting/escaping would be:
ARRAY['{"country_code": [{"code": "GB01F290/00"}]}'::jsonb,' {"country_code": [{"code": "GB21F290/41"}]}']
A way to obtain that value given your input would be with this query:
select array_agg(jsonb_build_object(
'country_code',
jsonb_build_array(jsonb_build_object( 'code', x))
)) from
jsonb_array_elements('["GB01F290/00", "GB21F290/41"]')
But there might be better ways of doing that, in python.
Then the query would be:
select * from thetable where country_code #> ANY($1::jsonb[])
Where $1 holds the value given in the first block, or the result of the expression given in the 2nd block or the result of the query given in the third block. You could also put combine the queries into one by putting the first into the second as a subquery, but that might inhibit use of indexes.
Note that the column country_code needs to be of type jsonb, not json, for this to work. But that is what it should be anyway.
It would probably be better if you chose a different way to store your data in the first place. An array of objects where each object has a unique name (the value of "code", here) is an antipattern, and should instead be an object of objects, with the unique name being the key. And having objects which just have one key at the top level, which is the same as the name of the column, is another antipattern. And what is the point of "new":1 if it is always present (or is that just an artifact of the example you chose)? Does it convey any meaning? And if you remove all of that stuff, you are left with just a list of strings. Why use jsonb in the first place for that?

Postgres performance implications in storing json array data as type jsonb or jsonb[]

considering a model like the below with a json array of bars:
const myModel = {
id: 1,
bars: [
{
aproperty: 10
},
{
anotherproperty: 'fred'
}]
}
are there any performance implications when defining the bars column as type of jsonb and simply adding the array as json, or storing the array items within a jsonb[] array?
The bars array will not be modified much and simply firehosed in, but will be queried.
It's strongly depends on task what you will do over data. JSON is just text with syntax check. Jsonb is recursive binary structure with complex data format. JSON should be shorter, and has fast serialization - but slower parsing. Jsonb should be longer with longer serialization, but parsing (reading) is faster.
The main important differences is smarter indexing on Jsonb.
PostgreSQL nonatomic types are immutable - that's means so update doesn't modify old value - it does copy and new value is updated and stored. On large values the update is very expensive.

How to do querying, sorting and filtering on values of an object in mongodb?

I am trying to find a way to do querying, sorting and filtering on values of an object(which is again an object) in a mongo document. The document structure is,
{
_id: '',
uid: '12345',
objects:{
dkey1: {
prop1: val1,
prop2: val2,
...
},
dkey2: {
prop1: val1,
prop2: val2,
...
},
dkey3: {
prop1: val1,
prop2: val2,
...
},
dkey4: {
prop1: val1,
prop2: val2,
...
}
...
}
}
objects property can contain 1000s of objects with dynamic keys. Thery are hash based unique keys. When I get these objects, I don't want to return all. I want to query, sort, limit as it can be done if they are from different documents. For example, if I say prop1 = val1 sort by prop2 limit 10, the query should return first 10 sub-objects in the objects, where their prop1 is val1 sorted by prop2.
I think it cannot be done with normal find. So, I am trying with aggregation framework. In first stage I will do match on uid. Next? I am confused there. Instead of objects with dynamic keys, if it is an array of objects, I can do $unwind and in further stages, I could've done filter on inner properties(prop1, prop2...), sorting and applying limit etc. But the problem is, it is not an array of objects. If there is a way to convert values of objects object into array of objects, it would be easier. I was looking for the way, but I could not find a solution.
I know the structure is not good and changing the schema would help me. But I am in a situation, I cannot change it now. Is there a way to convert objects's values into array of objects? Or is there different way to achieve the same result with some other aggregation pipeline stages?
Why can't this be done with normal find? According to the documents aggregation operations is to "group values from multiple documents together", and if I understood correctly that's not what you want to do here.
Try this:
db.objects.find({prop1: 'val1'}).sort({prop2: 1}).limit(10)
This was tested in mongo shell
objects would be your collection
the number 1 on sort means ascending order, -1 would be descending
and the number 10 on limit is the limit value of course
--- Edit ----
If you want to access to properties of documents inside another document, use the dot notation.
Example: db.objects.find({'nestedobj.prop1': 'val1'})
--- Edit 2 ---
Now I see I misunderstood your question. Sory. The problem here is that I don't think there is an operator that will let you access any embedded document (I really don't know, I can look into it but not right now).
But maybe I can help you telling you that if you are going to use 'aggregate', '$match' would be to filter the results, so uid wouldn't be on that pipeline stage. MongoDB 2.4 provides support for Javascript functions executed at database, but the purpose of the aggregation framework, as I told you before, is to map reduce the documents, so this isn't the best case scenario. I would be concerned about the performance and the ability of the database engine to accomplish what you want. But I think it should be tested before dismissing the idea.
Sorry again for misunderstanding your question and I hope you can solve your problem. Let me know if you do and how!