I've been testing Couchbase 5 and created a bucket called fp-conversion-data which has some JSON data in it. I have been trying to run some simple queries such as:
SELECT * FROM fp-conversion-data limit 5;
Instead of getting the expected results, I keep getting this error:
[
{
"code": 4010,
"msg": "FROM expression term must have a name or alias",
"query_from_user": "SELECT * FROM fp-conversion-data limit 5;"
}
]
I think the problem is that you have dashes in the name of the bucket. Use backticks (`) around the bucket name.
Try this:
SELECT *
FROM `fp-conversion-data`
LIMIT 5;
Related
I have made a query on a data and it returns a result:
[ RowDataPacket { 'COUNT(t.id)': 2 } ]
How can I access it like the count number?
I have tried result.COUNT(t.id) but it isn't worked.
The way the object is named, you need to access it like so:
result[0]["COUNT(t.id)"]
I would rather name the columns explicitly by using aliases in the query:
select count(t.id) as count_of_id
from ...
The data in the column looks like the below:
{
"activity": {
"token": "e7b64be4-74d4-7a6d-a74b-xxxxxxx",
"route": "http://example.com/enroll/confirmation",
"url_parameters": {
"Success": "True",
"ContractNumber": "003992314W",
"Barcode": "1908Y10Z",
"price": "8.99"
},
"server_info": {
"cookie": [
"_ga=xxxx; _fbp=xxx; _hjid=xxx; XDEBUG_SESSION=XDEBUG_ECLIPSE;"
],
"upgrade-insecure-requests": [
"1"
],
},
"campaign": "Unknown/None",
"ip": "192.168.10.1",
"entity": "App\\Models\\User",
"entity_id": "1d9f3066-13ce-4659-b10d-xxxxx",
},
"time": "2021-05-21 20:15:02"
}
My code that I am using is below:
SELECT *
FROM websote.stored_events
WHERE JSON_EXTRACT(event_properties, '$.route') = 'http://example.com/enroll/confirmation'
ORDER BY created_at DESC LIMIT 500;
The code works on the other the json values just not the url ones. I've tried escaping the values in MySQL like the below:
SELECT *
FROM websote.stored_events
WHERE JSON_EXTRACT(event_properties, '$.route') = 'http:///example.com//enroll//confirmation'
ORDER BY created_at DESC LIMIT 500;
But still no luck. Any help on this would be appreciated!
Route is a nested property; I would have expected the path to be
JSON_EXTRACT(event_properties, '$.activity.route')
Your example data isn't valid JSON. You can't have a comma after the last element in an object or array:
"entity_id": "1d9f3066-13ce-4659-b10d-xxxxx",
},
^ here
If I remove that and other similar cases, I can test your data inserts into a JSON column and I can extract the object element you described:
mysql> select json_extract(event_properties, '$.activity.route') as route from stored_events;
+------------------------------------------+
| route |
+------------------------------------------+
| "http://example.com/enroll/confirmation" |
+------------------------------------------+
Note the value is returned with double-quotes. This is because it's returned as a JSON document, a scalar string. If you want the raw value, you have to unquote it:
mysql> select json_unquote(json_extract(event_properties, '$.activity.route')) as route from stored_events;
+----------------------------------------+
| route |
+----------------------------------------+
| http://example.com/enroll/confirmation |
+----------------------------------------+
If you want to search for that value, you would have to do a similar expression:
select * from stored_events
where json_unquote(json_extract(event_properties, '$.activity.route'))
= 'http://example.com/enroll/confirmation'
Searching based on object properties stored in JSON has disadvantages.
It requires complex expressions that force you (and anyone else you needs to maintain your code) to learn a lot of details about how JSON works.
It cannot be optimized with an index. This query will run a table-scan. You can add virtual columns with indexes, but that adds to complexity and if you need to ALTER TABLE to add virtual columns, it misses the point of JSON to store semi-structured data.
The bottom line is that if you find yourself using JSON functions in the WHERE clause of a query, it's a sign that you should be storing the column you want to search as a normal column, not as part of a JSON document.
Then you can write code that is easy to read, easy for your colleagues to maintain, and can be optimized easily with indexes:
SELECT * FROM stored_events
WHERE route = 'http://example.com/enroll/confirmation';
You can still store other properties in the JSON document, but the ones you want to be searchable should be stored in normal columns.
You might like to view my presentation How to Use JSON in MySQL Wrong.
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 new to couchbase and I have been going through couchbase documents and other online resources for a while but I could't get my query working. Below is the data structure and my query:
Table1:
{
"jobId" : "101",
"jobName" : "abcd",
"jobGroup" : "groupa",
"created" : " "2018-05-06T19:13:43.318Z",
"region" : "dev"
},
{
"jobId" : "102",
"jobName" : "abcd2",
"jobGroup" : "groupa",
"created" : " "2018-05-06T22:13:43.318Z",
"region" : "dev"
},
{
"jobId" : "103",
"jobName" : "abcd3",
"jobGroup" : "groupb",
"created" : " "2018-05-05T19:11:43.318Z",
"region" : "test"
}
I need to get the jobId which has the latest job information (max on created timestamp) for a given jobGroup and region (group by jobGroup and region).
My sql query doesn't help me using self-join on jobId.
Query:
/*
Idea is to pull out the job which was executed latest for all possible groups and region and print the details of that particular job
select * from (select max(DATE_FORMAT_STR(j.created,'1111-11-11T00:00:00+00:00')) as latest, j.jobGroup, j.region from table1 j
group by jobGroup, region) as viewtable
join table t
on keys meta(t).id
where viewtable.latest in t.created and t.jobGroup = viewtable.jobGroup and
viewtable.region = t.region
Error Result: No result displayed
Desired result :
{
"jobId" : "102",
"jobName":"abcd2",
"jobGroup":"groupa",
"latest" :"2018-05-06T22:13:43.318Z",
"region":"dev"
},
{
"jobId" : "103",
"jobName" : "abcd3",
"jobGroup" : "groupb",
"created" : " "2018-05-05T19:11:43.318Z",
"region" : "test"
}
If I understand your query correctly, this can be answered using 'group by' and no join. I tried entering your sample data and the following query gives the correct result:
select max([created,d])[1] max_for_group_region
from default d
group by jobGroup, region;
How does it work? It uses 'group by' to group documents by jobGroup and region, then creates a two-element array holding, for every document in the group:
the 'created' timestamp field
the document where the timestamp came from
It then applies the max function on the set of 2-element arrays. The max of a set of arrays looks for the maximum value in the first array position, and if there's a tie look at the second position, and so on. In this case we are getting the two-element array with the max timestamp.
Now we have an array [ timestamp, document ], so we apply [1] to extract just the document.
I'm seeing some inconsistencies and invalid JSON in your examples, so I'm going to do the best I can. First off, I'm using Couchbase Server 5.5 which provides the new ANSI JOIN syntax. There might be a way to do this in an earlier version of Couchbase Server.
Next, I created an index on the created field: CREATE INDEX ix_created ON bucketname(created).
Then, I use a subquery to get the latest date, aggregated by jobGroup and region. I then join the latest date from this query to the entire bucket and select the fields that (I think) you want in your desired result:
SELECT k.jobId, k.jobName, k.jobGroup, k.created AS latest, k.region
FROM (
SELECT j.jobGroup, j.region, MAX(j.created) as latestDate
FROM so j
GROUP BY j.jobGroup, j.region
) dt
LEFT JOIN so k ON k.created = dt.latestDate;
Problems with this approach:
If two documents have the exact same date, this isn't a reliable way to determine the latest. You can add a LIMIT 1 to the subquery, which would just pick one arbitrarily, or you could ORDER BY whatever your preference is.
Subquery performance: I don't know how large your data set is, but this could be pretty slow.
Requires Couchbase Server 5.5, which is currently in beta.
If you are using a different version of Couchbase Server, you may want to consider asking in the Couchbase N1QL Forums for a more expert answer.
I have this queries:
select otherDocKey from bucket use keys '1234'
update bucket use keys 'hear I need the result of the first query' set ...
I want to do something like that:
update bucket use keys (select otherDocKey from bucket use keys '1234') set kuku = 3
but the response I get is:
[
{
"code": 5030,
"msg": "Missing or invalid primary key map[otherDocKey:\"56443\"] of type map[string]interface {}."
}
]
is there a way to do that in one query?
I am using couchbase version 4.5
The problem with your query is that the nested subquery returns a json result. I.e., the query:
select otherDocKey from bucket use keys '1234'
will return a result that looks like:
{"otherDocKey":"This_is_the_key_for_the_other_doc"}
But you don't want json, you just want the value from the json. For that you need to use 'select raw'. E.g.,
select raw otherDocKey from bucket use keys '1234'
That should give you a result that looks like:
["This_is_the_key_for_the_other_doc"]
When the subquery returns that kind of result, the "use keys" should work properly.