N1QL: Using select directly on arrays - couchbase

I am having problems on querying objects inside an array.
I have this sample document
{
...
status: 'active',
current: { ... },
history: [
{
id: '73bae187-1101-4fb3-a71a-2bbf90026eb3',
date: '2017-03-28T09:32:22.884Z',
content: 'This is second content'
},
{
id: 'd6a6c63d-42db-4ef5-88e9-616cfe539a57',
date: '2017-03-25T09:32:22.884Z',
content: 'This is first content'
},
{
id: '3fbdb846-2b55-4ff8-8960-86997ef31556',
schedule: '1970-01-01T00:00:00.000Z',
content: 'This is a very old content'
}
]
}
I want to directly query from the history array sub document in which I want to apply date filters.
Is it possible in n1ql to retrieve the history array that will only contain the objects that satisfies the condition?
Can I apply a limit to which I can control the number of the the returned objects inside the array?
I tried some queries using splicing [0:$1] where limit is an input but doesn't work when the limit is greater than the array size.
Thanks for the help.

Try either of the following approach:
SELECT h[0:least(ARRAY_LENGTH(h), $arraylimit)] As h FROM default As d
LET h = ARRAY v FOR v IN d.history WHEN v.id IN [ 'xyz', 'pqr'] END;
Or:
SELECT h[0:least(ARRAY_LENGTH(h),$limit)] As h (SELECT ARRAY_AGG(h) As h
FROM default As d UNNEST d.history As h WHERE h.id IN [ 'xyz', 'pqr'] GROUP BY d) As q;

Related

mySQL/Sequelize - how to query to get data whose field is empty array

My http request will return below data:
It returns below data:
Users.js
{
{
...
friends:[]
},
{
...
friends:[{id:xxx,...},...]
},
{
...
friends:[]
},
}
If I want to use query to get all data whose friends array is [],
should I do below query.
select * from users where (what should I write here)
If friends is a direct column in your database is JSON array. You can use JSON_LENGTH to find out the length of array.
SELECT JSON_LENGTH('[1, 2, {"a": 3}]'); // Output: 3
SELECT JSON_LENGTH('[]'); // Output: 0
You can use same concept to get data from your database.
select *
FROM users
WHERE JSON_LENGTH(friends) = 0;
If you've nested JSON and one of key is friends in that json for given column(data) then your query would be like using JSON_CONTAINS
SELECT *
FROM users
WHERE JSON_CONTAINS(data, JSON_ARRAY(), '$.friends') -- To check do we have `friends` as key in that json
and JSON_LENGTH(data, '$.friends') = 0; -- To check whether it is empty array.
Now you can convert it to sequelize query. One of the way you can use is
Model.findAll({
where: {
[Op.and]: [
Sequelize.literal('RAW SQL STATEMENT WHICH WONT BE ESCAPED!!!')
]
}
})
Make sure to update Model with your user model and query.

Angular 8 make football match using JSON

i want to create football matches using this JSON:
export const teams: Array<any> = [
{
name: 'A',
teams: [
{
name: 'France',
},
{
name: 'Portugual',
},
{
name: 'india',
},
{
name: 'china',
}
]
},
]
so for example i want to make matches france vs india than france vs china .
so i am using Angular 8 , and i have some issues if anyone can help me in that code .
HTML:
<div class="col-3" *ngFor="let group of group1">
<h5>{{ group }}</h5>
</div>
TypeScript:
this.group1 = this.teams;
this.teams.forEach((item, index) => {
this.groupList.push(item.name);
item.teams.forEach((item, index) => {
this.group1.push(item.name);
});
});
What I believe you want to do is display a list of all possible matches within this JSON, and I assume that since the teams array is in it's own array of objects with a name tag, that there may be separate groups of matches that you wish to display.
I have created a Stackblitz project you can view here to see my implementation of what I believe it is you are looking for.
I will explain my code below.
HTML:
<div class="col-3" *ngFor="let group of groupList">
<h5>{{ group }}</h5>
</div>
I wasn't sure what the difference between 'group1' and 'groupList' were supposed to be in your code, so I have selected groupList as my display value, and use 'group1' as a property in the TS.
TS:
for (let teamGroup of this.group1) {
this.groupList.push("Group: " + teamGroup.name); // show the group
for (let team1 of teamGroup.teams) {
for (let team2 of teamGroup.teams) {
// iterate over every possibility of two teams facing each other
if (
this.groupList.indexOf(
String(team1.name + " vs. " + team2.name)
) === -1 &&
this.groupList.indexOf(
String(team2.name + " vs. " + team1.name)
) === -1
) {
// filter out matchups already pushed to the array
if (team1.name !== team2.name) {
// filter out self-matches
this.groupList.push(team1.name + " vs. " + team2.name);
}
}
}
}
}
In the Stackblitz implementation, I'm using 'teams' as a property of my component, assigned to the JSON you provided, but you can get this JSON dynamically and use this code, just make sure to assign the value to the 'group1' property.
The 'groupList' property is an empty array, which we will .push() the values we wish to display to. By looping over the 'teams' array within the first (and only) entry in your JSON, we can decide on a display format for the string (I have chosen 'Team1 vs. Team2') and compare all possible matchups between two teams within the group against entries in 'groupList'. If the matchup does not exist, we will push the matchup to 'groupList'.
The end result is this:
Results
I hope this was what you were looking for. I would have asked a clarifying question in the comments first, but I'm too new to the website to be able to.

How to output an array to a comma-deliniated string?

I have an array called device, which looks like this (simplified):
label : "Device 1",
exhibits : [{
item : 1,
desc : "This is a sample"
},{
item : 2,
desc : "This is another sample"
},{
item : 3,
desc : "This is a third"
}]
I'm trying to print exhibits neatly for a PDF, so I'm thinking comma-deliniated like this:
1, 2, 3
This is my code:
<cfloop array="#device.exhibits#" index="exhibit">
#exhibit.item#
</cfloop>
But I get this:
123
Yes, I could manually figure out if there should be commas or not, but is there a better way to do this?
Since you're using CF11+, you can use the ArrayMap function with an ArrayList to turn the array into a list.
exhibits.map( function(i) { return i.item ; } ).toList() ;
With your example array, it gives you "1,2,3".
In another of my answers, I stepped through handling empty elements. Since this is an array of structs, I don't know if this would be a problem. How are you getting this data for your exhibits array?
EDIT:
exhibits.map( function(i) { return i.item ; } )
.filter( function(j) { return len(j) ; } )
.toList() ;
will return the list with empty elements removed.
EDIT 2:
Per the question by #TravisHeeter, if you prefer lambda expressions or arrow functions, you can use them in Lucee 5.
exhibits.map( (i) => i.item ).filter( (j) => len(j) ).toList()
https://trycf.com/gist/907a68127ddb704611b191d494aa94ce/lucee5?theme=monokai
The usual approach is to extract the data first:
<!--- extract the itemNumber of every exhibit --->
<cfset itemNumberList = []>
<cfloop array="#device.exhibits#" index="exhibit">
<cfset itemNumberList.add(exhibit.itemNumber)>
</cfloop>
And then we transform the extracted data to a comma-separated list (string):
<cfset itemNumberList = arrayToList(itemNumberList, ", ")>
<!--- 1, 2, 3 --->
<cfoutput>#itemNumberList#</cfoutput>
Array-mapping (see Shawn's answer) is a more fancy (readable?) way.

Transform JSON array to a JSON map

I have a postgresql table called datasource with jsonb column called config. It has the following structure:
{
"url":"some_url",
"password":"some_password",
"username":"some_username",
"projectNames":[
"project_name_1",
...
"project_name_N"
]
}
I would like to transform nested json array projectNames into a map and add a default value for each element from the array, so it would look like:
{
"url":"some_url",
"password":"some_password",
"username":"some_username",
"projectNames":{
"project_name_1": "value",
...
"project_name_N": "value"
}
}
I have selected projectNames from the table using postgresql jsonb operator config#>'{projectNames}', but I have no idea how to perform transform operation.
I think, I should use something like jsonb_object_agg, but it converts all data into a single row.
I'm using PostgreSQL 9.6 version.
You need to first unnest the array, then build a new JSON document from that. Then you can put that back into the column.
update datasource
set config = jsonb_set(config, '{projectNames}', t.map)
from (
select id, jsonb_object_agg(pn.n, 'value') as map
from datasource, jsonb_array_elements_text(config -> 'projectNames') as pn (n)
group by id
) t
where t.id = datasource.id;
The above assumes that there is a primary (or at least unique) column named id. The inner select transforms the array into a map.
Online example: http://rextester.com/GPP85654
are you looking for smth like:
t=# with c(j) as (values('{
"url":"some_url",
"password":"some_password",
"username":"some_username",
"projectNames":[
"project_name_1",
"project_name_N"
]
}
'::jsonb))
, n as (select j,jsonb_array_elements_text(j->'projectNames') a from c)
select jsonb_pretty(jsonb_set(j,'{projectNames}',jsonb_object_agg(a,'value'))) from n group by j
;
jsonb_pretty
------------------------------------
{ +
"url": "some_url", +
"password": "some_password", +
"username": "some_username", +
"projectNames": { +
"project_name_1": "value",+
"project_name_N": "value" +
} +
}
(1 row)
Time: 19.756 ms
if so, look at:
https://www.postgresql.org/docs/current/static/functions-aggregate.html
https://www.postgresql.org/docs/current/static/functions-json.html

Get corresponding time and value from json using Django (Python 2)

The following is a sample of the JSON that I'm fetching from the source. I need to get certain values from it such as time, value, value type. The time and value are in different arrays and on different depth.
So, my aim is to get the time and value like for value 1, I should get the timestamp 1515831588000, 2 for 1515838788000 and 3 for 1515845987000.
Please mind that this is just a sample JSON so ignore any mistakes that I may have made while writing this array.
{
"feed":{
"component":[
{
"stream":[
{
"statistic":[
{
"type":"DOUBLE",
"data":[
1,
2,
3
]
}
],
"time":[
1515831588000,
1515838788000,
1515845987000
]
}
]
}
]
},
"message":"",
"success":true
}
Here is a function, that I have written to get the values but the timestamp that I'm getting on the final step is incorrect. Please help to resolve this issue.
get_feed_data() is the function that is giving the above JSON.
# Fetch the component UIDs from the database
component_uids = ComponentDetail.objects.values('uid')
# Make sure we have component UIDs to begin with
if component_uids:
for component_uid in component_uids:
# Fetch stream UIDs for each component from the database
stream_uids = StreamDetail.objects.values('uid').filter(comp_id=ComponentDetail.objects.get(uid=component_uid['uid']))
for stream_uid in stream_uids:
feed_data = json.loads(get_feed_data(component_uid['uid'], stream_uid['uid']))
sd = StreamDetail.objects.get(uid=stream_uid['uid'])
for component in feed_data['feed']['component']:
for stream in component['stream']:
t = {}
d = {}
stats = {}
for time_value in stream['time']:
t = time_value
for stats in stream['statistic']:
for data_value in stats['data']:
print({
'uid': sd, value_type:stats['type'], timestamp=t, value=data_value
})
I finally got it dome using lists. I simply append the data in a list and call it later in a loop using the index and fetch the corresponding date and time.