I have a nest operation that joins an array of ids with some documents.
SELECT left.*,right FROM bucket AS left
LEFT NEST bucket AS right
ON META(right).id IN left.array
Result
[
{
array : ["rightId1","rightId2"],
right : [ { < rightFields1 > }, { < rightFields2 > } ]
}
]
I need the returned documents (< rightFields >) have the id on one of its fields, how can I do this?
META(item).id only works in case item is bucket alias otherwise it returns MISSING.
First 2 are right approach in this case as you have right side document keys.
SELECT left.*,
(SELECT META(r).id, r.*
FROM bucket AS r USE KEYS left.array) AS right
FROM bucket AS left;
OR
SELECT left.*, right
FROM bucket AS left
LET right = (SELECT META(r).id, r.*
FROM bucket AS r USE KEYS left.array);
If you need really process right document and use them as array instead of NEST (for no processing) you should Use JOIN, GROUP BY and ARRAY_AGG()
SELECT left.*,
ARRAY_AGG(OBJECT_ADD(right,"id",META(right).id)) AS right
FROM bucket AS left
LEFT JOIN bucket AS right ON KEYS left.array
GROUP BY left;
I don't know if there is an easier solution, but I solved it by iterating each item of the array with ARRAY, and adding it a new property with OBEJECT_ADD
SELECT left.*,ARRAY OBJECT_ADD(item, "id", META(item).id) FOR item IN right END
FROM bucket AS left
LEFT NEST bucket AS right
ON META(right).id IN left.array
Related
I'm starting to explore the JSON1 library for sqlite and have been so far successful in the basic queries I've created. I'm now looking to create a more complicated query that pulls data from multiple levels.
Here's the example JSON object I'm starting with (and most of the data is very similar).
{
"height": 140.0,
"id": "cp",
"label": {
"bind": "cp_label"
},
"type": "color_picker",
"user_data": {
"my_property": 2
},
"uuid": "948cb959-74df-4af8-9e9c-c3cb53ac9915",
"value": {
"bind": "cp_color"
},
"width": 200.0
}
This json object is buried about seven levels deep in a json structure and I pulled it from the larger json construct using an sql statement like this:
SELECT value FROM forms, json_tree(forms.formJSON, '$.root')
WHERE type = 'object'
AND json_extract(value, '$.id') = #sControlID
// In this example, #sControlID is a variable that represents the `id` value we're looking for, which is 'cp'
But what I really need to pull from this object are the following:
the value from key type ("color_picker" in this example)
the values from keys bind ("cp_color" and "cp_label" in this example)
the keys value and label (which have values of {"bind":"<string>"} in this example)
For that last item, the key name (value and label in this case) can be any number of keywords, but no matter the keyword, the value will be an object of the form {"bind":"<some_string>"}. Also, there could be multiple keys that have a bind object associated with them, and I'd need to return all of them.
For the first two items, the keywords will always be type and bind.
With the json example above, I'd ideally like to retrieve two rows:
type key value
color_picker value cp_color
color_picker label cp_label
When I use json_extract methods, I end up retrieving the object {"bind":"cp_color"} from the json_tree table, but I also need to retrieve the data from the parent object. I feel like I need to do some kind of union, but my attempts have so far been unsuccessful. Any ideas here?
Note: if the {"bind":"<string>"} object doesn't exist as a child of the parent object, I don't want any rows returned.
Well, I was on the right track and eventually figured out it. I created a separate query for each of the items I was looking for, then INNER JOINed all the json_tree tables from each of the queries to have all the required fields available. Then I json_extracted the required data from each of the json fields I needed data from. In the end, it gave me exactly what I was looking for, though I'm sure it could be written more efficiently.
For anyone interested, this is what hte final query ended up looking like:
SELECT IFNULL(json_extract(parent.value, '$.type'), '_window_'), child.key, json_extract(child.value, '$.bind') FROM (SELECT json_tree.* FROM nui_forms, json_tree(nui_forms.formJSON, '$') WHERE type = 'object' AND json_extract(nui_forms.formJSON, '$.id') = #sWindowID) parent INNER JOIN (SELECT json_tree.* FROM nui_forms, json_tree(nui_forms.formJSON, '$') WHERE type = 'object' AND json_extract(value, '$.bind') != 'NULL' AND json_extract(nui_forms.formJSON, '$.id') = #sWindowID) child ON child.parent = parent.id;
If you have any tips on reducing its complexity, feel free to comment!
I have a document with the structure { doc.data.role.level }, I want to access to level property,
but using this query
SELECT r.data.role.level FROM `hostel` r where r.id = '12345678Z'
I got the error
"msg": "syntax error - at role",
but with those query I got no results
SELECT r.data.`role`.level FROM `hostel` r where r.id = '12345678Z'
SELECT `r.data.role.level` FROM `hostel` r where r.id = '12345678Z'
If there are special characters in fields/identifiers or reserve keywords you must escape them with back-ticks(i.e. escaped identifiers) as described https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/identifiers.html
Example 1:
"role" is reserve keyword
{
"id":"12345678Z",
"data":{"role":{"level":3}}
}
SELECT r.data.`role`.level
FROM hostel AS r
WHERE r.id = "12345678Z";
Example 2:
Field has special character dot. You must escape whole field name (to interpret as field vs nested document).
{
"id":"12345678Z",
"data.role.level":5
}
SELECT r.`data.role.level`
FROM hostel AS r
WHERE r.id = "12345678Z";
Example 3:
hostels is array. If you are looking inside array you must use ANY syntax.
{
"hostels": [ { "id":"12345678Z"},
{ "id":"34545678Z"}}
]
"data":{"role":{"level":3}}
}
SELECT r.data.`role`.level
FROM hostel AS r
WHERE ANY h IN r.hostels SATISFIES h.id = "12345678Z" END;
You're on the right track with backticks to escape reserved words.
If you aren't getting an error message, then I suspect it's your WHERE clause. Are you sure your documents have an "id" field in them?
{ "id": "12345678Z", "foo": "bar", ... etc ... }
Or are you trying to query based on the document ID (in the below screenshot there is no "id" field in the document)?
If the latter, then you should use META().id:
SELECT * FROM `testbucket` r where META(r).id = '12345678Z'
I know this might seem a bit confusing, but "id" isn't a magic field in Couchbase. It's a field just like any other. The actual ID of the document is in the document's metadata.
Also, a recommendation: if you are trying to get a single document by its ID, you're much better off using the key/value API instead of a N1QL query. No need to involve the overhead of query/index services.
I am trying to delete objects from my JSON array in MySQL.
I have a table called cart with two fields quote_id type int and items type json with the following row stored inside MySQL
quote_id: 0
items:
[
{
"a":42,
"b":"test4"
},
{
"a":32,
"b":"test3"
}
]
I am trying to create a query which would delete json objects from the json array. For example every
{
"a":32,
"b":"test3"
}
I have tried many queries. First I ended up with this:
UPDATE cart
SET items = IFNULL(JSON_REMOVE(items, JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3'))), items)
WHERE quote_id = 13392;
However it just deletes "b":"test3" from the second object and left the "a":32 in it and I need a query that would find the whole object and would delete it.
This is my second query:
UPDATE cart
SET items = IFNULL(JSON_REMOVE(items, JSON_SEARCH(items, 'one', CAST('{"a": 32, "b": "test3"}' AS JSON))), items)
WHERE quote_id = 13392;
However I don't think the search on it works. I tried it without using the CAST()AS JSON, however it still did not work.
As I said I am pretty sure the problem is with the JSON_SEARCH, but maybe someone has the solution?
Thank you!
The JSON_SEARCH returns the path of the property, not the path to the object itself.
So you can use the following solution to get the object path with SUBSTR:
SELECT JSON_REMOVE(items,
SUBSTR(JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')), 1, LOCATE('.', JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')))-1)
) FROM cart
You can also use REGEXP_SUBSTR to get the object path:
SELECT JSON_REMOVE(items, REGEXP_SUBSTR(JSON_UNQUOTE(JSON_SEARCH(items, 'one', 'test3')), '^\\$\\[[0-9]+\\]'))
FROM cart
demo on dbfiddle.uk
can anyone help me with querying many to many relation tables in postgres?
i have tables:
> 1.exercise(id,name)
> 2.tag(id,label)
> 3.tag_in_exercise(id,exercise_id,tag_id)
let say, that we have one exercise bonded with two tags via tag_in_exercise
when using query :
select e.id,t.label from exercise e
left join tag_in_exercise te on e.id=te.exercise_id
left join tag t on te.tag_id=t.id
i will receive json
[ { id: 1,
label: 'basic1' },
{ id: 1,
label: 'basic2' }]
but i want to receive it as nested json
[ { id: 1,
tags:[ {'basic1'},{'basic2'} ]
}]
is it possible to get that by using standart postgresql queries or i need to use some ORM?
or if exists another solution please let me know,
thanks
PostgreSQL does not return the JavaScript object you have posted. Your node driver is converting an array of arrays returned by PostgreSQL, which the driver is converting to JavaScript objects.
However, you can have PostgreSQL return a structure which I suspect will be converted how you wish by using array_agg.
Try this:
SELECT e.id,array_agg(t.label) AS label
FROM exercise e
LEFT JOIN tag_in_exercise te on e.id=te.exercise_id
LEFT JOIN tag t on te.tag_id=t.id
GROUP BY e.id;
You will get a raw PostgreSQL result in the structure you want, which hopefully the driver will translate as you intend:
id | label
----+-----------------
1 | {basic1,basic2}
2 | {NULL}
I am writing website using play 2.0 framework. And I have a problem when parsing results.
This request to mysql db gets all the links(can be several per episode) added to the database per episode together with all the information about episode and anime.
def lastReleasedLink(limit:Long=5):List[(((Episode,Anime),Link),Genre)] = {
DB.withConnection { implicit c =>
SQL(
"""
select * from yas_episodes as a
inner join anime as b on a.ep_anime_id=b.id
left outer join yas_links as c on a.ep_id=c.ep_id
LEFT JOIN yas_animes_genres AS d ON a.ep_anime_id = d.ag_anime_id
INNER JOIN yas_genres AS e ON e.g_id = d.ag_genre_id
where c.ep_id IS NOT NULL group by c.ep_id order by c.date desc limit {limit}
""").on('limit ->limit)as(Episode.simple~Anime.simple~Link.simple~Genre.simple map{
case episode~anime~link~genre => episode -> anime -> link -> Genre
} *)
}
}
The return value is type of List[(((Episode,Anime),Link),Genre)]
but how can I form output to the list of
let say List[episode,anime,Seq[links]] or List[episode,anime,Seq[Genres],Seq[links]] don't know where to put genres.
You can imagine that when you have two links per one episode information from table anime and yas_episodes will be copied for every row. So I need somehow stack them together(group) by episode record. Then it will be possible to iterate list and access to all objects.
As you can see, in the request there is many-to-many relation of anime with genres.
I have no idea how can I put all together to one list to be able to access it in view. Should Genre be part of Anime model?
It seems that the preferred way to achieve this is using the Scala collection API, see this post by Guillaume Bort.
In your case, I think you could do something like
lastReleasedLink groupBy { case (((e, a), l), g) => (e, a) }
to group by (Episode, Anime). Generally speaking, those manipulations are probably a little easier if you change your function to return a List[(Episode, Anime, Link, Genre)], i.e.
case episode~anime~link~genre => (episode, anime, link, genre)
then you could achieve the same with this code:
lastReleasedLink groupBy ((_._1, _._2))