MySQL: Update specific values in JSON array of objects - mysql

I'm using MySQL 5.7.12, and have a JSON column with the following data:
[{"tpe": "I", "val": 1}, {"tpe": "C", "val": 2}, {"tpe": "A", "val": 3}]
I would like to UPDATE val from 2 into 20 WHERE tpe='C'.
Here is my attempt:
UPDATE user SET data = JSON_SET(data->"$[1]", '$.val', 20);
This does update the value but it trims the other elements in the array and it becomes only a json-object, here how it looks after the update:
{"tpe": "C", "val": 20}
How can I get this right?
2nd question: is there a way to dynamically get the json object in the array so I don't have to hard code "$[1]" ? I tried to use JSON_SEARCH ??

Related

How to search a JSON db

Do you by any chance know how I should structure my search to access the 'a', 'b', 'c' in the following:
{"_default": {"1": {"Pc": "2429546524130460032", "Pf": "2429519276857919232", "Points": [{"P": "2428316170619108992", "a": "0.0690932185744956", "b": "2.6355498567408557", "c": "0.4369495787854096"}...
Where there are a total of 10 Points in several thousand objects (the "1" at the beginning is the first object). I am able to access "Pc" and "Pf", but if I try:
db.search(Point.Points['a'] == '0.0690932185744956'
I get an empty set.
Thoughts?

How to only keep properties from a Postgres jsonb object that exist in an array of keys?

I have a jsonb object with numerous properties, and I have a Postgres array of keys that I want to extract from the object, into a new, stripped-down object.
If my object is:
'{"foo": true, "bar": 2, "baz": "cat", "other": "Some text"}'::jsonb
and my array of properties to extract is '{foo,other}', my desired result is:
'{"foo": true, "other": "Some text"}'::jsonb
How can I achieve this?
Borrowing from this answer...
select jsonb_object_agg(key,value)
from jsonb_each('{"foo": true, "bar": 2, "baz": "cat", "other": "Some text"}'::jsonb)
where key = any('{foo,other}')
jsonb_each turns the JSON into a table of key (text) and value (jsonb) columns which can then be queried normally.
where key = any('{foo,other}') is basically where key in ('foo', 'other') but for arrays.
Finally jsonb_object_agg(key,value) aggregates all the matched rows into one JSON object.
You could do it like this:
SELECT jsonb_object_agg(elem.key, elem.val)
FROM (jsonb_each(
JSONB '{"foo": true, "bar": 2, "baz": "cat", "other": "Some text"}'
) AS elem(key, val)
JOIN (unnest(
TEXT[] '{foo,other}'
) AS filter(key) USING (key);

How to get a list of object keys in JMESPath

My Google search skills are failing me. How to get a list of all JSON object keys in JMESPath?
i.e. how to go from:
{"a": 1, "b": 2}
to:
["a", "b"]
JMESPath has the function keys. Therefore, the JMESPath expression is keys(#).
Example
echo '{"a": 1, "b": 2}' | jp "keys(#)"
returns
[
"a",
"b"
]
Tested with jp 0.1.3 on a Linux environment.

Replacing JSON file with CSV for d3js

http://bl.ocks.org/robschmuecker/7880033
I'm new to javascript and d3. The above example is a dendrogram. I can create my own. However, if I wanted to use it for something like employee data, it seems like it would be a pain to always having to be editing the json unless I'm missing some easier trick.
A csv in excel, that I've used in other charts, would seem like it would work well. Is It possible to replace the flare.json with a csv with the data? if so , how?
No, it's not possible directly. To know why, you'll have to understand the way the function d3.csv creates an array. Suppose you have this CSV:
foo, bar, baz
21, 33, 5
1, 14, 42
When parsed, it will generate a single array of objects, without nested arrays or nested objects. The first row defines the key names, and the other rows the values. This is the array generated for that CSV:
[
{"foo": 21, "bar": 33, "baz": 5},
{"foo": 1, "bar": 14, "baz": 42}
]
Or, if you don't change the type, with the numbers as strings:
[
{"foo": "21", "bar": "33", "baz": "5"},
{"foo": "1", "bar": "14", "baz": "42"}
]
You will not get anywhere close of what you want, which is an array of objects containing arrays containing objects containing arrays etc...
You can modify this array later to create the nested children you need (look at #torresomar comment below), but it's way easier to simply edit your JSON.

Merge several json arrays in circe

Let's say we have 2 json arrays. How to merge them into a single array with circe? Example:
Array 1:
[{"id": 1}, {"id": 2}, {"id": 3}]
Array 2:
[{"id": 4}, {"id": 5}, {"id": 6}]
Needed:
[{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, {"id": 6}]
I've tried deepMerge, but it only keeps the contents of the argument, not of the calling object.
Suppose we've got the following set-up (I'm using circe-literal for convenience, but your Json values could come from anywhere):
import io.circe.Json, io.circe.literal._
val a1: Json = json"""[{"id": 1}, {"id": 2}, {"id": 3}]"""
val a2: Json = json"""[{"id": 4}, {"id": 5}, {"id": 6}]"""
Now we can combine them like this:
for { a1s <- a1.asArray; a2s <- a2.asArray } yield Json.fromValues(a1s ++ a2s)
Or:
import cats.std.option._, cats.syntax.cartesian._
(a1.asArray |#| a2.asArray).map(_ ++ _).map(Json.fromValues)
Both of these approaches are going to give you an Option[Json] that will be None if either a1 or a2 don't represent JSON arrays. It's up to you to decide what you want to happen in that situation .getOrElse(a2) or .getOrElse(a1.deepMerge(a2)) might be reasonable choices, for example.
As a side note, the current contract of deepMerge says the following:
Null, Array, Boolean, String and Number are treated as values, and values from the argument JSON completely replace values from this JSON.
This isn't set in stone, though, and it might not be unreasonable to have deepMerge concatenate JSON arrays—if you want to open an issue we can do some more thinking about it.