API Design - Returning Data from several years - json

I'm currently designing a new API.
One of the methods should return some data about a basic object and there are some numeric values that are changing over the years.
Here is a basic example of the object :
{
"id" : 1,
"city_name" : "New York",
"inhabitants" : 10000,
"houses" : 100
}
The goal of the API is to be able to retrieve this data over the years and to pass a table of years as input parameter.
(Also should you pass a table if you only need one year of data ?)
So here are the input parameters :
{
"id" : 1,
"years" : ["2020", "2021"]
}
What is the best data structure to return the data over the years ? Is it Restful ?
The API should be designed to be used by several external consumers.
Here are my experiments so far :
1 - Returning a table like :
[
{
"2020" : {
"id" : 1,
"city_name" : "New York",
"inhabitants" : 9000,
"houses" : 90
}
},
{
"2021" : {
"id" : 1,
"city_name" : "New York",
"inhabitants" : 10000,
"houses" : 100
}
}
]
The problem is that you would need to parse the table and each entry to use the values for a specific year.
2 - Returning the values nested :
{
"id" : 1,
"city_name" : "New York",
"inhabitants" : {
"2021" : 10000,
"2020" : 9000
}
"houses" : {
"2021" : 100,
"2020" : 90
}
}

I think it really depends on what you want to do with the view model the REST API returns. You can support multiple view models if you create multiple REST resources for it:
/api/x/1
{
"id" : 1,
"city_name" : "New York",
"inhabitants" : 10000,
"houses" : 100
}
/api/x/1/history
[
{
"year": "2020",
"id" : 1,
"city_name" : "New York",
"inhabitants" : 9000,
"houses" : 90
},
{
"year": "2021",
"id" : 1,
"city_name" : "New York",
"inhabitants" : 10000,
"houses" : 100
}
]
/api/x/1/events
[
{
"type": "change",
"year": "2020",
"inhabitants" : 9000,
"houses" : 90
},
{
"type": "change",
"year": "2021",
"inhabitants" : 10000,
"houses" : 100
}
]
/api/x/1/plot
[
{
"year": "2020",
"inhabitants" : 9000,
"houses" : 90
},
{
"year": "2021",
"inhabitants" : 10000,
"houses" : 100
}
]
So instead of having a single general view model I would make separate view models fulfilling very specific needs. If you don't understand what your consumers need, then ask them. In my experience guessing takes several months and the consumers can tell you the same info in 5 mins.

Related

converted json result structure not same as source

i have test case to compare against the source kept in Kafka message.
I noticed the structured is not same.
no missing field, but the structure is not arranged in the same sequence.
how do i make the result converted same as the source structure?
code to retrieve the message, then decode the base64 format and prettyprint the result.
def responseList = new JsonSlurper().parseText(consumeMessage.getResponseText())
println('response text: \n' + JsonOutput.prettyPrint(JsonOutput.toJson(responseList)))
def decoded = new JsonSlurper().parseText(new String(responseList[0].value.decodeBase64()))
println('response decoded text: \n' + JsonOutput.prettyPrint(JsonOutput.toJson(decoded)))
below is the result printed at console
2019-11-20 16:36:44.934 DEBUG oingDRToAllocationVerification-DynamicID - 10: decoded = JsonSlurper().parseText(new java.lang.String(responseList[0].value.decodeBase64()))
2019-11-20 16:36:44.945 DEBUG oingDRToAllocationVerification-DynamicID - 11: println("response decoded text:
" + JsonOutput.prettyPrint(JsonOutput.toJson(decoded)))
response decoded text:
{
"contexts": [
{
"activityId": "c2884e63-d30d-48a3-965c-0b33202885c2",
"incomingTimestamp": "2019-11-20T08:36:29.0829958Z",
"sourceName": "DispenseOrderService",
"timestamp": "2019-11-20T08:36:29.0829958+00:00",
"userId": "unknown"
}
],
"dispenseOrder": [
{
"dispenseRequestType": "DISPENSEORDER",
"id": "6320112019043628",
"items": [
{
"administrationInstructions": "drug intake information test 123",
"dispenseAsWritten": false,
"id": "cda92ec7-3191-4b7b-a972-7f4545146db4",
"itemId": "Augmentn",
"quantity": 100
},
{
"administrationInstructions": "drug intake information test 234",
"dispenseAsWritten": false,
"id": "19e00776-b08d-47c8-930b-76ddc01f0ff4",
"itemId": "Clopidogrl",
"quantity": 200
},
{
"administrationInstructions": "drug intake information test 456",
"dispenseAsWritten": true,
"id": "0a5b0f4a-366d-4fa7-a0b8-2e8c83f4af13",
"itemId": "Adenosine",
"quantity": 300
}
],
"locationId": "Pharmacy Jewel East",
"piiIdentifiers": {
"doctorId": "b502f046-fb1e-4fcf-8135-a7a13cfb47f6",
"patientId": "fe49b461-8eeb-46d5-b995-a31cdaaa35f3",
"pharmacistId": "b502f046-fb1e-4fcf-8135-a7a13cfb47f6"
},
"priority": 4,
"state": "NEW",
"type": "Test ingest type"
}
],
"messageClass": "DispenseRequestV1",
"messageId": "83e94dac-dfb6-49d7-8ca0-219d155fecce",
"notifications": [
],
"operation": "Add",
"timestamp": "2019-11-20T08:36:29.0952632+00:00"
}
below is the source. the result after conversion is not same as source. as in the structure is not arranged accordingly.
{
"operation" : "Add",
"dispenseOrder" : [ {
"id" : "6320112019043628",
"locationId" : "Pharmacy Jewel East",
"piiIdentifiers" : {
"patientId" : "fe49b461-8eeb-46d5-b995-a31cdaaa35f3",
"doctorId" : "b502f046-fb1e-4fcf-8135-a7a13cfb47f6",
"pharmacistId" : "b502f046-fb1e-4fcf-8135-a7a13cfb47f6"
},
"priority" : 4,
"state" : "NEW",
"type" : "Test ingest type",
"dispenseRequestType" : "DISPENSEORDER",
"items" : [ {
"id" : "cda92ec7-3191-4b7b-a972-7f4545146db4",
"itemId" : "Augmentn",
"quantity" : 100,
"dispenseAsWritten" : false,
"administrationInstructions" : "drug intake information test 123"
}, {
"id" : "19e00776-b08d-47c8-930b-76ddc01f0ff4",
"itemId" : "Clopidogrl",
"quantity" : 200,
"dispenseAsWritten" : false,
"administrationInstructions" : "drug intake information test 234"
}, {
"id" : "0a5b0f4a-366d-4fa7-a0b8-2e8c83f4af13",
"itemId" : "Adenosine",
"quantity" : 300,
"dispenseAsWritten" : true,
"administrationInstructions" : "drug intake information test 456"
} ]
} ],
"messageId" : "83e94dac-dfb6-49d7-8ca0-219d155fecce",
"timestamp" : "2019-11-20T08:36:29.0952632+00:00",
"messageClass" : "DispenseRequestV1",
"contexts" : [ {
"userId" : "unknown",
"timestamp" : "2019-11-20T08:36:29.0829958+00:00",
"activityId" : "c2884e63-d30d-48a3-965c-0b33202885c2",
"incomingTimestamp" : "2019-11-20T08:36:29.0829958Z",
"sourceName" : "DispenseOrderService"
} ],
"notifications" : [ ]
}
As json.org says:
An object is an unordered set of name/value pairs.
So, different JSON methods/libraries might order them in a different way. You shouldn't rely on order of name/value pairs when working with JSON.
(If order is very important to you, you might try using suggested solution from this post.)

Can this JSON with "timestamp" : Double format be aggregated for SUM, AVG in MongoDB

I have imported the above json data into it's own collection on mongoDB database. I'm trying to aggregate the values (ie 40, 30, 30) and SUM and AVG them as they reside in the inner most embedded document. I'm having a problem doing this when I try using dot notation and can not get any vaules. I feel the unique timestamps (ie 1567544426000, 1567541464000, 1567541475000) are a problem. Is this json file formatted correctly for aggregation and how would I do so. Thanks for any help or if you can even point me in the right direction where I can find out how to do SUM, AVG etc to the data.
I've tried use NoSQLBooster and Query ASsist for MongoDB
{
"Barcode": "97-1908-577-1032-BE1-332",
"IP": "192.162.656.111",
"VFD": {
"CurrentPV": {
"Type": "Speed",
"Data": {
"1567544426000": 40,
"1567541464000": 30
"1567541475000": 30
}
},
"CurrentSP": {
"Type": "Speed",
"Data": {
"1567544426000": 55,
"1567541464000": 5
"1567541488000": 10
}
},
"Program_Running": {
"Type": "Active",
"Data": {
"1567544426000": 1,
"1567541464000": 0
"1567541475000": 3
}
}
},
"Equipment": "PieceOfEquipment",
"Location": "Garage",
"RunEnd": "NA",
"RunStart": 1533541438
}
I can't seem to reach the values even when I use dot notation down to the "Data" branch object (ie Equipment.VFD.CurrentPV.Data) but no result sets are returned.
We can convert the VFD.CurrentPV.Data into an array of key-value pairs using $objectToArray and then perform SUM and AVG on the values itself.
The following query can get us the expected output:
db.collection.aggregate([
{
$addFields:{
"data":{
$objectToArray: "$VFD.CurrentPV.Data"
}
}
},
{
$project:{
"sum":{
$sum:"$data.v"
},
"avg":{
$avg:"$data.v"
}
}
}
]).pretty()
Data set:
{
"_id" : ObjectId("5d830f3afb35a835fbd8638e"),
"Barcode" : "97-1908-577-1032-BE1-332",
"IP" : "192.162.656.111",
"VFD" : {
"CurrentPV" : {
"Type" : "Speed",
"Data" : {
"1567544426000" : 40,
"1567541464000" : 30,
"1567541475000" : 30
}
},
"CurrentSP" : {
"Type" : "Speed",
"Data" : {
"1567544426000" : 55,
"1567541464000" : 5,
"1567541488000" : 10
}
},
"Program_Running" : {
"Type" : "Active",
"Data" : {
"1567544426000" : 1,
"1567541464000" : 0,
"1567541475000" : 3
}
}
},
"Equipment" : "PieceOfEquipment",
"Location" : "Garage",
"RunEnd" : "NA",
"RunStart" : 1533541438
}
Output:
{
"_id" : ObjectId("5d830f3afb35a835fbd8638e"),
"sum" : 100,
"avg" : 33.333333333333336
}

F# - Compare 2 JsonValue'

I have 2 Json values that are similar, but there are some differences.
Json1:
{
"id": "1",
"people" : [
{
"Id" : 1421,
"Name" : "Jackson",
"Age" : 21,
"Status" : "Available"
},
{
"Id" : 5916,
"Name" : "Steven",
"Age" : 22,
"Status" : "Available"
}
],
"totalRecords" : 2
}
Json2:
{
"id": "1",
"people" : [
{
"Id" : 1421,
"Name" : "Jackson",
"Age" : 21,
"Status" : "Available"
},
{
"Id" : 5916,
"Name" : "Steven",
"Age" : 22,
"Status" : "Unavailable"
},
{
"Id" : 1337,
"Name" : "Alice",
"Age" : 19,
"Status" : "Available"
}
],
"totalRecords" : 3
}
I'd like to know if there's a way to compare the two Jsonvalues. At the moment I de-serialize the data into a type and then use the Id's and the status' to see if anythings changed. I then pick out the parts that are different (In the example it'd be Steven and Alice) and add them to a sequence for later.
I'd like to reverse a few of the steps. I'd like too compare the json, find the differences, deserialize them and then add them to the sequence, or add them to the sequence then de-serialize the whole sequence. Either way, same result.
Any ideas?

Operation on mongodb array elements

I am new to mongodb. I am developing a social network website, for which I have entries in my collection "users". I have the following entry of particular user.
{
"_id" : ObjectId("56a9fd3a5b4e12369150d6f0"),
"name" : "Amit",
"venue" : {
"state" : "Madhya Pradesh",
"city" : "Gwalior",
"ll" : [
"26.2215",
"78.1780"
]
},
"lsv" : [
0.05,
0.17,
0.05,
0.14,
0.18,
0.24,
0.17
],
"username" : "amit",
"frnds" : [
{
"id" : "udit",
"type" : 1
},
{
"id" : "nakul",
"type" : 1
}
]
}
For each user I have to do operation on "lsv" array by matching some values of "lsv" of another user.
I am not able to get how to write the query for that.

How do I query a nested object in MongoDB?

I have a JSON schema that looks like this:
{
"_id" : ObjectId("5692a3e124de1e0ce2dfda22"),
"title" : "A Decade of Decadence, Pt. 2: Legacy of Dreams",
"year" : 2013,
"rated" : "PG-13",
"released" : ISODate("2013-09-13T04:00:00Z"),
"runtime" : 65,
"countries" : [
"USA"
],
"genres" : [
"Documentary"
],
"director" : "Drew Glick",
"writers" : [
"Drew Glick"
],
"actors" : [
"Gordon Auld",
"Howie Boulware Jr.",
"Tod Boulware",
"Chen Drachman"
],
"plot" : "A behind the scenes look at the making of A Tiger in the Dark: The Decadence Saga.",
"poster" : null,
"imdb" : {
"id" : "tt2199902",
"rating" : 8,
"votes" : 50
},
"awards" : {
"wins" : 0,
"nominations" : 0,
"text" : ""
},
"type" : "movie"
}
I am trying to find a movie released in 2013, that is rated PG-13 and has won no awards. I tried the following query in my Mongo Shell but no luck:
db.movieDetails.find({rated: "PG-13", year:2013, awards: { wins : 0}})
Any ideas?
From the documentation:
When the field holds an embedded document, a query can either specify an exact match on the embedded document or specify a match by individual fields in the embedded document using the dot notation
db.movieDetails.find( { "rated": "PG-13", "year": 2013, "awards.wins" : 0 } )
if this PG-13 rating query would work for you:
db.movieDetails.find({"rated": "PG-13"})
then i would try something like this:
db.movieDetails.find({$and: [{"rated": "PG-13"}, {"year": 2013}, {"awards": { "wins" : 0}}]} )