I have a jsonb field in PostgreSQL with the following content:
{ "object": { "urls": "A;B;C" } }
What I want to do is update the value of urls inside the object and transform the string with semicolon separated values into a JSON array. So the result should look like this:
{ "object" : { "urls": ["A", "B", "C"] } }
I found out how to get a JSON array. Using
to_json(string_to_array(replace((json->'object'->'urls')::text, '"',''), ';'));
gives me ["A", "B", "C"] (I think there should be a better way of doing it without the conversion json -> text -> array -> json. Suggestions are welcome)
But how do I update the urls field with the json array now? Probably I have to use jsonb_set?
Use jsonb and the function jsonb_set():
create table my_table(id int primary key, jdata jsonb);
insert into my_table values
(1, '{ "object": { "urls": "A;B;C" } }');
update my_table
set jdata = jsonb_set(
jdata,
array['object', 'urls'],
to_jsonb(string_to_array(replace((jdata->'object'->'urls')::text, '"',''), ';'))
)
returning *;
id | jdata
----+-------------------------------------
1 | {"object": {"urls": ["A", "B", "C"]}}
(1 row)
Related
I have an array,
array = [1,2,3]
Need to transform it to:
newArray = [{id: 1}, {id: 2}, {id: 3}]
I know this, Is there any efficient way?
array.each { |id| newArray << { id: id } }
Anything like this?
array.map { |id| Hash[:id, id] }
the same with hash literal
array.map { |id| { id: id } }
A very elegant way:
convert to string
build the JSON style object
convert to array (inside the string)
let JSON parse it, for more (thread) safety
symbolize the keys, because in ruby it's preferred to use keys rather than strings
additionally you could use Base58 random key and hash it twice to mitigate timing attacks
JSON.parse([1,2,3].map(&:to_s).collect{ "{\"id\": \"#{_1}\"}" }.join(",").prepend("[").concat("]")).collect(&:symbolize_keys)
=> [{:id=>"1"}, {:id=>"2"}, {:id=>"3"}]
I have converted a dataframe with columns email, account, id into json using toJSON. Each row is a JSON which looks like: {"email": "xyz", "account": "pqr", "id": "1"}.
The id field is not unique and I want to combine this array of JSON into array of JSON array such that each row is a array of JSONs with same id values.
For example: One row would look like: [{"email": "xyz", "account": "pqr", "id": "1"},{"email": "abc", "account": "lmn", "id": "1"}]
After this, I want to populate this JSON array into another dataframe user which has columns id and user.
The JSON array of each user with the matching id should be in the user dataframe.
O/p would be each row as: | 1 | [{"email": "xyz", "account": "pqr", "id": "1"},{"email": "abc", "account": "lmn", "id": "1"}] |
Can someone suggest how I can do this efficiently without exploding all the arrays multiple times?
I'm unsure which JSON library you are using, so I'd recommend to convert to a case class which has an id field. You could then group by the id field and then insert into your user dataframe, converting the grouped rows to JSON.
Something along the lines of...
case class Row(email: String, account: String, id: String)
val rows: List[Row] = ??? // converted from your dataframe
rows.groupBy(_.id)
.map { case (id, rows) =>
// insert into user dataframe. Convert rows to JSON
}
I have Array[Row] called arr (I obtained it after df.collect()) that I want to pass in my JSON string as key and value pairs:
val result = """{"field1": "A", "arr": [""" + arr + """]}"""
It should be:
{"field1": "A", "arr": [
{"name":"Ford", "model": "Fiesta"},
{"name":"Ford", "model": "Mustang"},
...
]}
If I do it the way that I showed above, it will not work.
Should I iterate over this array and manually define each parameter?:
arr.get(i).get(arr.get(i).fieldIndex("field1")).toString()
You should be doing as below by using .toJSON as suggested by philantrovert in comments of the question
val result = """{"field1":"A","arr":"""+df.toJSON.collectAsList()+"""}"""
If you are using arr variable then you can do
val arr = df.toJSON.collectAsList()
val result = """{"field1":"A","arr":"""+arr+"""}"""
I have a array of values, some of the values in the array may already be present in my database. I want to upsert the new values and increase the count of the old values.
One way to do this is :
For all the values that are present in the database use a update command and increment count. It can be done using : db.test.update({ link: {$in: ["A", "B"]}}, {$inc: {count: 1}}, {upsert: true, multi:true})
For all the values not present in my database, check each and every value and upsert it into the database.
The second step may put some load on the network. Is there any way to do the second step in one command?
For example consider this:
Initial state of my database:
{ "_id" : ObjectId("5a45f97f84527190e1f28cb7"), "link" : "A", "count" : 3 }
and I have the array as following: const values = ['A', 'B', 'C']
Now I want to have something like this:
{"_id": ObjectId("abc"), "link": "A", "count" : 4},
{"_id": ObjectId("xyz"), "link": "B", "count" : 1},
{"_id": ObjectId("fgh"), "link": "C", "count" : 1}
To achieve the second step (as you mentioned) optimally you can perform lookup in your DB using find() method.
If the array value isn't present in the DB, then find() is gonna return an empty object. So you just see the length of the object returned from find(). If found empty, insert into DB else update the info.
Example code for nodejs environment:
var db = mongojs('dbname', ['collection_name']);
var theLink = 'XYZ';
db.collection_name.find({link: theLink}, function (err, obj) {
if (err)
throw err;
if (obj.length == 0)
// write logic to insert
else
// write logic to update
});
I am using Mongo C APIs to implement DB Interface for a project.
MongoDB Document:
{
_id,
... // Some fields
...
Array
}
Query Used to Populate Values in the Array:
BCON_APPEND (&query, "$push", "{",
"Array", "{",
"Key", key,
"Value", (char*)value, "}",
"}");
Populated Array inside MongoDB:
"Array" : [ { "Key": "key1", "Value" : "string1" },
{ "Key": "key2", "Value" : "string2" },
{ "Key": "key3", "Value" : "string3" },
]
Query used to find the matching row in the array:
BCON_APPEND (&query, $elemMatch,
"Array", "{", "Key", key,
"}");
This query returns the complete document which contains a matching key in the array - which is fine.
Problem:
I am reading each field of the document returned by this query -- one by one.
When I encountered the Array field in the document -- my requirement is to get ONLY the matched row.
I tried to read the Array as follows:
uint32_t *document_len;
const uint8_t **document;
bson_iter_recurse (&iter, &sub_iter))
{
while (bson_iter_next (&sub_iter))
{
bson_iter_document (sub_iter,
&document_len,
document)
// Suppose my "Key" was: "key2"
// How to get the matching row: { "Key": "key2", "Value" : "string2" } as a String here ?
// Also, I want to receive ONLY matching row -- & NOT all 3 rows
}
}
I am not able to read String from this Array and also, not able to get only the matching row -- not all 3 rows.
[Note: In while() loop above, If I put this trace:
while (bson_iter_next (&sub_iter))
{
printf ("Found key \"%s\" in sub document.\n",
bson_iter_key (&sub_iter));
}
I get 3 prints:
Found key 0 in sub document
Found key 1 in sub document
Found key 2 in sub document
So, it is clear that -- I am getting all values from the array and NOT the only matching one and I cannot retrieve the actual strings from the array]
References:
Mongo C APIs https://api.mongodb.org/c/current/
libbson https://api.mongodb.org/libbson/current/bson_iter_t.html
Please help.