JSONiq count duplicates in array - json

I want to count duplicate values with JSONiq. I have following code:
jsoniq version "1.0";
import module namespace fetch = "http://zorba.io/modules/fetch";
let $tweets := parse-json(fetch:content("/tweets.json"))
let $users := parse-json(fetch:content("/users.json"))
return
let $different_languages :=
for $tweet in $tweets[]
return {
"name" : $tweet."metadata"."iso_language_code"
}
return [$different_languages]
This returns all the languages, but it opens a new pair for every language. It looks like this:
[ { "name" : "de" },
{ "name" : "da" },
{ "name" : "da" },
{ "name" : "da" }]
I want to return a JSON object that looks like this:
[ { "count" : 1, "language" : "de" },
{ "count" : 3, "language" : "da" }]
How can i achieve this?

This can be achieved with a group-by clause. This works like a SQL group by, but with an even finer level of control.
In the code below, the four objects in the unboxed $tweets array are grouped according to their language field ($tweet.metadata.iso_language_code). In each evaluation of the return clause, the grouping variable $language will contain the name of the language for the current group, and the non-grouping variable $tweet will contain the sequence of tweets that belong to the group. Calling count() on this sequence will return 3 and 1 respectively.
jsoniq version "1.0";
import module namespace fetch = "http://zorba.io/modules/fetch";
let $tweets := parse-json(fetch:content("/tweets.json"))
let $users := parse-json(fetch:content("/users.json"))
return
for $tweet in $tweets[]
group by $language := $tweet."metadata"."iso_language_code"
return { language: $language, count: count($tweet) }
Also, the quotes on metadata and iso_language_code are not needed. If needed, you can also wrap the result into an array, like so:
jsoniq version "1.0";
import module namespace fetch = "http://zorba.io/modules/fetch";
let $tweets := parse-json(fetch:content("/tweets.json"))
let $users := parse-json(fetch:content("/users.json"))
return [
for $tweet in $tweets[]
group by $language := $tweet.metadata.iso_language_code
return { language: $language, count: count($tweet) }
]
There is no restriction on the expression in the return clause: $language and $tweet are variables like any others and they can be used as inputs to any JSONiq expression. For instance, instead of counting the tweets, one can also nest them in the output, as the data model is arborescent:
return { language: $language, count: [ $tweet ] }

Related

Couchbase N1q1 update array element and return only the updated block

I want to update an element in an array object and return only the few elements from the updated array object.
Document:
{
"doctype" : "report",
"name":"nick",
"emailId":"nick123#gmail.com",
"subjects" : [{
"name":"SOA",
"tutor":"roshan",
"classes" : "12",
"mark" : 40,
"subid": "5678"
},
{
"name":"UNIX",
"tutor":"mathew",
"classes" : "9"
"mark" : 50,
"subid" : "3788"
}
],
"id" : "12345"
}
n1q1:
update bucket1
Set i.status = “pass” for i in subjects when i.mark > 40 end
where doctype = "report"
returning *
above query returns the whole document but I want only few element from the updated array object like below. Can you please help me on this . Thanks
Expected query response
{
"id" : "12345",
"subid: “3788”,
"name":"UNIX"
}
Returning clause you can build expression that you want.
You are updating ARRAY, it means it can update more than one element. so you can return as ARRAY, if you want FIRST element replace with ARRAY with FIRST.
UPDATE bucket1 AS b
SET i.status = "pass" FOR i IN b.subjects WHEN i.mark > 40 END
WHERE b.doctype = "report" AND (ANY v IN b.subjects SATISFIES v.mark > 40 END)
RETURNING (ARRAY {v.id, v.subid, v.name} FOR v IN b.subjects WHEN v.mark > 40 END) AS subjects;
You can only return modified info, you will not able to return original info.

Bulk insert rows from an array to an sql server with golang

I have a list of structs as follows
row = [
{
"name":<name1>,
"age" :<age1>,
"job" :<job1>
},
{
"name":<name1>,
"age" :<age1>,
"job" :<job1>
},
{
"name":<name1>,
"age" :<age1>,
"job" :<job1>
},
etc...
]
I want to insert this into an SQL table. So far I was running a loop through the array and inserting each row one by one. But is there any other way by which I can insert all the rows with just one query? I know bulk insert, but my understanding is that, for bulk insert, I will have to import data from an external file. I don't want to do that. How do I use the data from this array and perform bulk insert?
type Person struct {
Name string
Age int
Job string
}
func InsertPeople(db *sql.DB, personSlice []*Person) error {
var queryString = `INSERT INTO "person_table" (
"name"
, "age"
, "job"
) VALUES `
numOfFields := 3
params := make([]interface{}, len(personSlice)*numOfFields)
for i, p := range personSlice {
pos := i * numOfFields
params[pos+0] = p.Name
params[pos+1] = p.Age
params[pos+2] = p.Job
queryString += `(?, ?, ?),`
}
queryString = queryString[:len(queryString)-1] // drop last comma
_, err := db.Exec(queryString, params...)
return err
}
You aren't going to be able to do any kind of super-optimized bulk insert without placing a file on the server I don't think.
I am not sure if the db library supports it but using the SQLX extension you can build a single insert statement with named bindvars that go against a struct. You can then pass an array of these structs to a method like NamedExec.
Something like this:
users := []User{
{
Name: "alex",
Email: "alex#example.com",
},
{
Name: "muhammed",
Email: "muhammed#example.com",
},
}
db.NamedExec("insert into users (NAME, EMAIL) values (:Name, :Email);", users)

How to get each field of json doc in XQUERY Marklogic?

How to get each field of json doc in XQUERY Marklogic?
let $doc :=
{
"field1" :'t',
"field2" : 'th',
"filed4": 'the'
}
return
$doc//??,
{
"New Filed" : "Added"
}
So how can we get the output like below ?
{ "field1" :'t', "field2" : 'th', "filed4": 'the' ,"New Filed" : "Added"}
One approach: use the xdmp:from-json() to convert the immutable JSON node to a mutable map and then set the field:
return xdmp:from-json($doc) => map:with("NewField", "Added")
For more detail, see: https://docs.marklogic.com/xdmp:from-json
Hoping that helps,
A JSON object is really just a specialized map. So you can use map operators, like the + union operator:
let $doc := object-node
{
"field1" :'t',
"field2" : 'th',
"filed4": 'the'
}
return
$doc + map:entry("NewField", "added")

Is there a way to randomize the jsonPath array number in get[] myJson?

I have a list of values that I can use for the title field in my json request. I would like to store a function in the common.feature file which randomizes the title value when a scenario is executed.
I have attempted using the random number function provided on the commonly needed utilities tab on the readme. I have generated a random number successfully, the next step would be using that randomly gernerated number within the jsonpath line in order to retrieve a value from my data list which is in json.
* def myJson =
"""
{
"title" : {
"type" : "string",
"enum" : [
"MR",
"MRS",
"MS",
"MISS"
[...]
]
}
}
"""
* def randomNumber = random(3)
* def title = get[0] myJson.title.enum
* print title```
The code above works but I would like to randomize the number within the get[0]. How is this possible in Karate?
I'm not sure of what you want, but can't you just replace 0 by randomNumber in get[randomNumber] myJson.title.enum ?

Passion in CouchBase Programming

I would like to get the single element in the Couchbase document that is in the array of objects, but i am able to fetch the array of objects
i tried to fetch the array using the following query, 'select countryDetails from test';
{
"type":"countries",
"docName":"CountryData",
"countryDetails":[
{
"name":"US",
"code":"+1",
"stateInfo":[
{
"name":"Florida",
"id":"1212"
},
{
"name":"NewYork",
"id":"1214"
}
]
},
{
"name":"France",
"code":"+33",
"stateInfo":[
{
"name":"Grand Est",
"id":"5212"
},
{
"name":"Brittany",
"id":"5214"
}
]
}
]
}
i tried fetching array using, select countryDetails from test;
i like to fetch the result as [ {"name" : "US", "code" : "+1" }, {"name" : "France", "code" : "+33"}]
If you project countryDetails it projects whole sub object.
If you need to part of sub object you need to explicitly project that.
The following ARRAY construction will provide the data representation you are expecting.
SELECT ARRAY {v.name,v.code} FOR v IN t.countryDetails END AS contryDetails
FROM test AS t
WHERE t.type = "countries";
What you are trying to do does not seem to be possible. You can get closer to what you want with a query like this:
select raw countryDetails from test
But the results of this query still have the result wrapped in an extra level of array.