I'm trying to group all occurrences of an ID's data into a JSON payload as an array - ksqldb

I'm new to KSQL and I feel like there should be a way to group and add data into an array
I'm getting these individual objects from the stream, for example
{
"ENRLMT_ID": "I12345",
"STUS_CD": "06",
"STUS_RSN_CD": "081",
"STUS_RSN_DESC": "APPROVED FOR REVALIDATION",
"STUS_DESC": "APPROVED"
}
{
"ENRLMT_ID": "I12345",
"STUS_CD": "13",
"SRC_ENRLMT_STUS_HSTRY_SK": "OxdP6jOQnr/o+UfE4q0zr5p7lMvK0Fh9N",
"STUS_RSN_CD": "029",
"STUS_RSN_DESC": "THE PROVIDER OR SUPPLIER IS VOLUNTARILY WITHDRAWING",
"STUS_DESC": "DEACTIVATED"
}
the results I'm looking to get is:
{
"ENRLMT_ID": "I12345",
PAYLOAD: [
{
"STUS_CD": "06",
"STUS_RSN_CD": "081",
"STUS_RSN_DESC": "APPROVED FOR REVALIDATION",
"STUS_DESC": "APPROVED"
},
{
"STUS_CD": "13",
"STUS_RSN_CD": "029",
"STUS_RSN_DESC": "THE PROVIDER OR SUPPLIER IS VOLUNTARILY WITHDRAWING",
"STUS_DESC": "DEACTIVATED"
}
]
}
This is the KSQL I've used to get as close as I could:
CREATE STREAM ENROLLMENT_STATUS_STREAM AS SELECT
ENRLMT_ID AS ENRLMT_ID,
STRUCT(
"STUS_CD":= ESJ.STUS_CD,
"STUS_RSN_CD" := ESJ.STUS_RSN_CD,
"STUS_RSN_DESC":= ESJ.STUS_RSN_DESC,
"STUS_DESC":= ESJ.STUS_DESC
) AS PAYLOAD
FROM ENROLLMENT_STATUS_DATA ESJ;
Resulting in this output from the stream:
{
"ENRLMT_ID": "I12345",
"PAYLOAD": {
"STUS_RSN_CD": "029",
"STUS_RSN_DESC": THE PROVIDER OR SUPPLIER IS VOLUNTARILY WITHDRAWING",
"STUS_CD": "13",
"STUS_DESC": "DEACTIVATED"
}
}

Yes it is possible using collect_list aggregate function
CREATE STREAM ENROLLMENT_STATUS_STREAM
AS
SELECT
ENRLMT_ID,
collect_list(struct(
STUS_CD := ESJ.STUS_CD,
STUS_RSN_CD := ESJ.STUS_RSN_CD,
STUS_RSN_DESC := ESJ.STUS_RSN_DESC,
STUS_DESC := ESJ.STUS_DESC
)) AS PAYLOAD
FROM ENROLLMENT_STATUS_DATA ESJ
GROUP BY ENRLMT_ID;

Related

How to return error messages per object in rego response when using nested objects

I am creating a policy to validate access to a collection of Records. These records are passed as input and have a collection of permissions attached to them. I validate them against permissions data stored in the OPA.
For instance, I can return the collection of Records that are accessible by doing something like this
isAllowed[id] {
permissionSet := {x | x := permissions.groups[_].name}
id := input.records[i].id
input.operation == "update"
input.records[i].acls.owners[j]==permissionSet[k]
}{
id := input.records[i].id
input.operation == "create" }
Which would return something like
"isAllowed": ["123"]
when the input is like the following and the 'permissions' data included "service.legal.user"
"input": {
"operation": "update",
"records": [
{ "id": "123", "acls": { "owners": ["service.legal.user"] }},
{ "id": "456", "acls": { "owners": ["service.storage.viewer"] }}
]
}
However I want to return something like the following where I list all input records and assign error messages to ones that have failed with all the reasons it failed
"records":[
{"id": "123", "errors": ""},
{"id": "456", "errors": "You must have owner permission to update a record"}
]
I have tried an incremental rule but I get the error message from OPA 'complete rules must not produce multiple outputs'
isAllowed = response {
#owner permission checked for update operation on all records
some i
response := {
"id" : input.records[i].id,
"errors" : CheckErrors
}
}
CheckErrors[reason] {
reason := "Must be an owner to update a record"
input.operation == "update"
permissionSet := {x | x := permissions.groups[_].name}
input.records[i].acls.owners[j]==permissionSet[k]
}
CheckErrors[reason]{
#no permission checked for create operation on all records
reason := "Anyone can create"
input.operation == "create"
}
Any help would be welcome.
Not sure I followed entirely, and you didn't provide the permissions object, but assuming groups is just a list of objects like {"name": "service.legal.user"} something like the below would produce your desired output.
records[response] {
id := input.records[_].id
errors := [r | e := check_errors[_]
e.id == id
r := e.reason]
response := {
"id" : id,
"errors" : errors
}
}
check_errors[{"id": id, "reason": "Must be an owner to update a record"}] {
input.operation == "update"
id := input.records[x].id
permissionSet := {x | x := permissions.groups[_].name}
owners := {o | o := input.records[x].acls.owners[_]}
count(owners & permissionSet) == 0
}
Full example here.

Is there a way to filter using count of a nested array item when using OData Query?

I am using Microsoft Graph List CalendarView to get calendar events from outlook. I would like to filter out items where count of attendees is 0. (Logically meaning time blocked for self).
I understand there is a $count parameter that will return the count of items. However, in the List CalendarView response i am not after the count of calendar items, but rather the count of attendees within each calendar item. And infact to use a not equal (ne) filter based on it.
{
"value": [
{
"originalStartTimeZone": "originalStartTimeZone-value",
"originalEndTimeZone": "originalEndTimeZone-value",
"iCalUId": "iCalUId-value",
"reminderMinutesBeforeStart": 99,
"isReminderOn": true,
"attendees":[
{
"type":"required",
"status":{
"response":"none",
"time":"0001-01-01T00:00:00Z"
},
"emailAddress":{
"name":"Samantha Booth",
"address":"samanthab#a830edad905084922E17020313.onmicrosoft.com"
}
},
{
"type":"required",
"status":{
"response":"none",
"time":"0001-01-01T00:00:00Z"
},
"emailAddress":{
"name":"Dana Swope",
"address":"danas#a830edad905084922E17020313.onmicrosoft.com"
}
}
]
}
]
}
I want to specifically filter out any event items where the array size of "attendees" is 0.
Is this feasible using OData query params?
It appears filtering against attendees property is not supported, see for example, this thread for a details. But the following approach could be considered:
a) introduce an extended property for event resource which will expose summary info (flag whether event contains attendees or the count of attendees) about attendees.
Update all the existing events:
PATCH https://graph.microsoft.com/v1.0/me/events/{event-id}
Content-Type: application/json
{
"singleValueExtendedProperties": [
{
"id":"String {66f5a359-4659-4830-9070-00047ec6ac6e} Name ContainsAttendes",
"value":"1"
}
]
}
b) now events could be filtered like this:
https://graph.microsoft.com/beta/me/events?$filter=singleValueExtendedProperties/Any(ep: ep/id eq 'String {66f5a359-4659-4830-9070-00047ec6ac6e} Name ContainsAttendes' and ep/value eq '1')
where it is assumed ContainsAttendes=1 corresponds to events which have one or more attendees

How can I use a complex query to retrieve data from Firebase?

I am try to create ios application for hotel booking. All my data are stored in firebase. My hotel's name and location are stored in "HotelLocation" table.
{
"HotelLocation": {
"H1": {
"name": "Ghetu hotel",
"location": "shonargao,dhaka"
},
"H2": {
"name": "BB hotel",
"location": "gulshan,dhaka"
},
"H3": {
"name": "Shuvashish hotel",
"location": "uttara,dhaka"
},
"H4": {
"name": "Bodi hotel",
"location": "uttara,dhaka"
}
}
}
This is my json format of table 'HotelLocation' but I am unable to retrieve data from this table for only 'uttara' i.e. if I search for uttara then I should get
Shuvashish hotel
Bodi hotel
I tried by using 'queryEqualToValue' but problem is that 'uttara,dhaka' because firebase is case sensitive. So ',dhaka' is creating problem.
Is there any way of using SQL Command "%LIKE%" in Firebase?
If you use queryStartingAt("uttara") and queryEndingAt("uttara") it will return the nodes you want.
You just can't do an exact search on a wildcard char.
There are a bunch of other ways to tackle this like...
Create a node for the location that references the hotels like this, then you can just read in that node and you have a list of the hotels:
uttara
H3: true
H4: true
Or another option is to create references to the locations - suppose the Shuvashish Hotel has locations in both uttara as well as shonargao. Deep query the Hotels node for locations/L1 = true would return H3
locations
L1: "uttara"
L2: "gulshan"
L3: "shonargao"
Hotels
H2
"name:": "BB hotel"
"locations"
L2: true
H3
"name": "Shuvashish hotel",
"locations"
L1: true
L3: true

Retrieving data using Grails Domain returns with a Class Key by default

I'm working with a Grails query service and I'm using these the code blocks to retrieve database rows via a domain class.
adjustmentCodeList = AdjustmentCode.findAll {
or {
ilike('description', "%$filterText%")
like('id', "%$filterText%")
}
}
adjustmentCodeList = AdjustmentCode.list()
adjustmentCodeList = AdjustmentCode.list(max: count, offset: from)
It works fine actually, but there is a little problem though. It returns the following list (some sensitive data are omitted):
[
{
"class": "rvms.maintenance.AdjustmentCode",
"id": ...,
"description": ...,
"lastUpdateBy": ...,
"lastUpdateDate": ...,
"status": ...,
"statusDate": ...,
"type": ...
},
{
"class": "rvms.maintenance.AdjustmentCode",
"id": ...,
"description": ...,
"lastUpdateBy": ...,
"lastUpdateDate": ...,
"status": ...,
"statusDate": ...,
"type": ...
},
...
{
"class": "rvms.maintenance.AdjustmentCode",
"id": ...,
"description": ...,
"lastUpdateBy": ...,
"lastUpdateDate": ...,
"status": ...,
"statusDate": ...,
"type": ...
}
]
It includes the domain class name. How can I remove the class key using some config? My current solution is to manually remove the class key from the list by iterating it inside a loop, removing that key one at a time. But maybe... there is another Grails-ly way.
If you want to see the domain, it looks like this:
package rvms.maintenance
import grails.util.Holders
import groovy.sql.Sql
import oracle.jdbc.OracleTypes
import java.sql.Connection
class AdjustmentCode implements Serializable {
String id
String description
String type
String status
Date statusDate
String lastUpdateBy
Date lastUpdateDate
static mapping = {
table '...'
version false
id column : '...'
description column : '...'
type column : '...'
status column : '...'
statusDate column : '...'
lastUpdateBy column : '...'
lastUpdateDate column : '...'
}
Map getAdjustmentCodeValues() {
Map values = [];
values << [id: this.getId()]
values << [description: this.getDescription()]
values << [type: this.getType()]
values << [status: this.getStatus()]
values << [statusDate: this.getStatusDate()]
values << [lastUpdateBy: this.getLastUpdateBy()]
values << [lastUpdateDate: this.getLastUpdateDate()]
return values
}
}
The Grails way to accomplish this is to customize the marshaller. I've explained how to do this with named marshallers in this answer and the same concept applies to your case as well (minus the named portion).

parsing a multi leve json file in Go Language

I need to parse and get values from fields in a json file.
[{"id": 27}, {"id": 0, "label": "Label 0"}, null, {"id": 93}, {"id": 85}, {"id": 54}, null, {"id": 46, "label": "Label 46"}]}}
Though i can work on single level , i am at a loss how i can iterate through levels here.
I have tried looking for an answer in google , various help sites and even stackoverflow.
I could not find any example that might help me in working with multi level json byte array.
Hope somebody can lead me to understand and work on it.
Thanks in advance
Just parse the JSON into an array of structs:
package main
import (
"encoding/json"
"fmt"
)
type Item struct {
Id int
Label string
}
func main() {
data := []byte(`[{"id": 27}, {"id": 0, "label": "Label 0"}, null, {"id": 93}, {"id": 85}, {"id": 54}, null, {"id": 46, "label": "Label 46"}]`)
var val []*Item
if err := json.Unmarshal(data, &val); err != nil {
fmt.Printf("Error: %s\n", val)
return
}
for _, it := range val {
fmt.Printf("%#v\n", it)
}
}
I hope this helps.

Resources