CosmosDB GeoSpatial Points Invalid - sql

I'm using Azure's cosmos DB, and testing via the sqlquery in the Azure portal. Some points in my collection are valid, some are not. I am unable to tell from the GeoJSON spec if I am missing requirements. All my points pass the geojsonlint test: https://geojsonlint.com/
What could be causing invalid points? The locations are setup the same as far as I can tell.
My Query:
SELECT *
FROM events1 e
WHERE ST_ISVALID(e.location)
Running the query returns that these are valid:
[
{
"id": "b4b49b65-dfad-40f3-943b-753553507d2c",
"name": "OG Olympics",
"location": {
"type": "Point",
"coordinates": [
41.900697426935544,
12.480266913771628
]
},
"events": "Hockey",
"time": "00:00:00",
"recurring": null,
"date": null,
"difficulty": "Expert",
"ages": "Senior",
"admin": null,
"private": null,
"_rid": "Maw1AIaRiRoHAAAAAAAAAA==",
"_self": "dbs/Maw1AA==/colls/Maw1AIaRiRo=/docs/Maw1AIaRiRoHAAAAAAAAAA==/",
"_etag": "\"11003fb9-0000-0700-0000-5f2f15cf0000\"",
"_attachments": "attachments/",
"_ts": 1596921295
},
{
"id": "f2d063e3-5654-475d-8e97-7412dc77fcfb",
"name": "Test Event DenverCC",
"location": {
"type": "Point",
"coordinates": [
100.2093,
-15.868
]
},
"events": "Basketball",
"time": "18:00:00",
"recurring": null,
"date": null,
"difficulty": "Intermediate",
"ages": "Senior",
"admin": null,
"private": null,
"_rid": "Maw1AIaRiRoJAAAAAAAAAA==",
"_self": "dbs/Maw1AA==/colls/Maw1AIaRiRo=/docs/Maw1AIaRiRoJAAAAAAAAAA==/",
"_etag": "\"1300a79d-0000-0700-0000-5f304fc80000\"",
"_attachments": "attachments/",
"_ts": 1597001672
},
{
"id": "10000",
"name": "OG Olympics 2",
"location": {
"type": "Point",
"coordinates": [
41.000697426935545,
-12.080266913771627
]
},
"events": "Hockey",
"time": "00:00:00",
"recurring": null,
"date": null,
"difficulty": "Expert",
"ages": "Senior",
"admin": null,
"private": null,
"_rid": "Maw1AIaRiRoKAAAAAAAAAA==",
"_self": "dbs/Maw1AA==/colls/Maw1AIaRiRo=/docs/Maw1AIaRiRoKAAAAAAAAAA==/",
"_etag": "\"13003499-0000-0700-0000-5f304d580000\"",
"_attachments": "attachments/",
"_ts": 1597001048
}
]
But it returns that these are invalid:
{
"id": "1000",
"name": "Sunday Morning Hockey",
"location": {
"type": "Point",
"coordinates": [
39,
-105
]
},
"events": "hockey",
"time": "09:00",
"recurring": "true",
"date": "2020-08-02",
"difficulty": "all levels",
"ages": "all ages",
"admin": "1000",
"private": "false",
"_rid": "Maw1AIaRiRoBAAAAAAAAAA==",
"_self": "dbs/Maw1AA==/colls/Maw1AIaRiRo=/docs/Maw1AIaRiRoBAAAAAAAAAA==/",
"_etag": "\"13008c9f-0000-0700-0000-5f3050d70000\"",
"_attachments": "attachments/",
"_ts": 1597001943
}
{
"id": "9f373e04-0cfc-4121-927d-a6256dbe06c6",
"name": "test1",
"location": {
"type": "Point",
"coordinates": [
39.731441899363105,
-104.98381230980158
]
},
"events": "Basketball",
"time": "00:00:00",
"recurring": null,
"date": null,
"difficulty": "Expert",
"ages": "Adult",
"admin": null,
"private": null,
"_rid": "Maw1AIaRiRoLAAAAAAAAAA==",
"_self": "dbs/Maw1AA==/colls/Maw1AIaRiRo=/docs/Maw1AIaRiRoLAAAAAAAAAA==/",
"_etag": "\"13005999-0000-0700-0000-5f304d760000\"",
"_attachments": "attachments/",
"_ts": 1597001078
}
{
"id": "be01bc12-d28e-4368-b6de-0f3e84dbe13c",
"name": "test2",
"location": {
"type": "Point",
"coordinates": [
39.72082849205111,
-104.98461395502092
]
},
"events": "Hockey",
"time": "00:00:00",
"recurring": null,
"date": null,
"difficulty": "Expert",
"ages": "Adult",
"admin": null,
"private": null,
"_rid": "Maw1AIaRiRoMAAAAAAAAAA==",
"_self": "dbs/Maw1AA==/colls/Maw1AIaRiRo=/docs/Maw1AIaRiRoMAAAAAAAAAA==/",
"_etag": "\"1300219a-0000-0700-0000-5f304de10000\"",
"_attachments": "attachments/",
"_ts": 1597001185
}

Took a while to realize, but GeoJSON expects flipped coordinates in the Point.
So while Maps return me a point type with [ latitude, longitude ]. GeoJSON expects [longitude, latitude]

Related

Is it correct to see a different cabin value aside that passed in the get FlightOffers APi as travelerClass?

From the documentation of the Get Route for the flight offers Api, I can add travelerClass as a filter to make a request. If I add say travelerClass as ECONOMY?
I expect to see only offers with ECONOMY. However I see that within the fareDetailsBySegment section in the result, I see that some Offers have their cabin values as other than ECONOMY. I see some with value of BUSINESS while others as PREMIUM_ECONOMY.
Is this proper?
My Concern
I want to be able to get all bookings that where ECONOMY based only. So I need to be sure that the flight offers returned in the first place are strictly limited by the travelerClass.
I will appreciate any clarity on the this issue. Also if there is a better way to go about this concern above, it will be most appreciated.
An example of my request is below:
Amadeus.shopping.flightOffersSearch.get({
originLocationCode: 'SYD',
destinationLocationCode: 'BKK',
departureDate: '2022-11-01',
adults: '1',
travelClass: 'ECONOMY'
}).then(...)
Offer with BUSINESS instead of ECONOMY
{
"type": "flight-offer",
"id": "22",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"lastTicketingDate": "2022-11-01",
"numberOfBookableSeats": 6,
"itineraries": [
{
"duration": "PT28H20M",
"segments": [
{
"departure": {
"iataCode": "SYD",
"terminal": "1",
"at": "2022-11-01T12:00:00"
},
"arrival": {
"iataCode": "PVG",
"terminal": "2",
"at": "2022-11-01T19:30:00"
},
"carrierCode": "MU",
"number": "562",
"aircraft": {
"code": "77W"
},
"operating": {
"carrierCode": "MU"
},
"duration": "PT10H30M",
"id": "13",
"numberOfStops": 0,
"blacklistedInEU": false
},
{
"departure": {
"iataCode": "PVG",
"terminal": "1",
"at": "2022-11-02T08:45:00"
},
"arrival": {
"iataCode": "BKK",
"at": "2022-11-02T12:20:00"
},
"carrierCode": "MU",
"number": "541",
"aircraft": {
"code": "320"
},
"operating": {
"carrierCode": "MU"
},
"duration": "PT4H35M",
"id": "14",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "EUR",
"total": "4048.84",
"base": "3858.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "4048.84"
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": true
},
"validatingAirlineCodes": [
"MU"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "EUR",
"total": "4048.84",
"base": "3858.00"
},
"fareDetailsBySegment": [
{
"segmentId": "13",
"cabin": "ECONOMY",
"fareBasis": "YSE0WDNQ",
"class": "Y",
"includedCheckedBags": {
"quantity": 2
}
},
{
"segmentId": "14",
"cabin": "BUSINESS",
"fareBasis": "QSE0WCNL",
"class": "Q",
"includedCheckedBags": {
"quantity": 2
}
}
]
}
]
}
in order to apply the filter for cabin class, I suggest you to try with POST method.
in POST method has more search criteria you can apply, below example is something that I have tried and it works: response only contains ECONOMY classes by updating values under cabinRestrictions.
details of the request model is available in API reference page
amadeus.shopping.flightOffersSearch.post(JSON.stringify({
"currencyCode": "USD",
"originDestinations": [
{
"id": "1",
"originLocationCode": "SYD",
"destinationLocationCode": "BKK",
"departureDateTimeRange": {
"date": "2022-11-01"
}
}
],
"travelers": [
{
"id": "1",
"travelerType": "ADULT"
}
],
"sources": [
"GDS"
],
"searchCriteria": {
"maxFlightOffers": 10,
"flightFilters": {
"cabinRestrictions": [
{
"cabin": "ECONOMY",
"coverage": "ALL_SEGMENTS",
"originDestinationIds": [
1
]
}
]
}
}
})).then(...)

Display data from an Api in the V-CALENDAR Vuetify Vuejs

I have the following data coming from my api:
[
{
"id": 1,
"start": "2020-12-24 01:00",
"end": "2020-12-24 01:30",
"comments": null,
"createdAt": "2020-12-24T19:37:52.699Z",
"updatedAt": "2020-12-24T19:37:52.699Z",
"clientId": 1,
"employeeId": null,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": null,
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 3,
"start": "2020-12-24 21:15",
"end": "2020-12-24 22:00",
"comments": null,
"createdAt": "2020-12-24T19:45:03.854Z",
"updatedAt": "2020-12-24T19:45:03.854Z",
"clientId": 1,
"employeeId": 1,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 2,
"start": "2020-12-24 01:00",
"end": "2020-12-24 02:00",
"comments": null,
"createdAt": "2020-12-24T19:39:19.184Z",
"updatedAt": "2020-12-24T19:39:19.184Z",
"clientId": 1,
"employeeId": 1,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 13,
"start": "2020-12-25 06:00",
"end": "2020-12-25 07:00",
"comments": "Fuck you",
"createdAt": "2020-12-25T16:24:10.893Z",
"updatedAt": "2020-12-25T16:24:10.893Z",
"clientId": 1,
"employeeId": 2,
"serviceId": 1,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Margareth",
"lastName": "Martins"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 14,
"start": "2020-12-25 01:00",
"end": "2020-12-25 06:00",
"comments": null,
"createdAt": "2020-12-25T22:08:40.878Z",
"updatedAt": "2020-12-25T22:08:40.878Z",
"clientId": 1,
"employeeId": 1,
"serviceId": 1,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 15,
"start": "2020-12-26 08:30",
"end": "2020-12-26 09:00",
"comments": null,
"createdAt": "2020-12-25T22:52:31.439Z",
"updatedAt": "2020-12-25T22:52:31.439Z",
"clientId": 1,
"employeeId": 1,
"serviceId": 1,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 10,
"start": "2020-12-23 09:00",
"end": "2020-12-23 09:30",
"comments": "é fodauuuuuuu",
"createdAt": "2020-12-25T15:12:20.790Z",
"updatedAt": "2020-12-25T15:12:20.790Z",
"clientId": 1,
"employeeId": null,
"serviceId": 1,
"appointmentStatusId": null,
"tenantId": 1,
"employee": null,
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 11,
"start": "2020-12-23 09:00",
"end": "2020-12-23 12:00",
"comments": "é fodauuuuuuu",
"createdAt": "2020-12-25T15:12:44.161Z",
"updatedAt": "2020-12-25T15:12:44.161Z",
"clientId": 1,
"employeeId": 1,
"serviceId": 1,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 4,
"start": "2020-12-25 01:00",
"end": "2020-12-25 05:00",
"comments": null,
"createdAt": "2020-12-25T02:32:32.574Z",
"updatedAt": "2020-12-25T02:32:32.574Z",
"clientId": 1,
"employeeId": 1,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 5,
"start": "2020-12-24 01:00",
"end": "2020-12-24 03:00",
"comments": "ghhhhhh",
"createdAt": "2020-12-25T02:36:52.243Z",
"updatedAt": "2020-12-25T02:36:52.243Z",
"clientId": 1,
"employeeId": 1,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 6,
"start": "2020-12-25 01:15",
"end": "2020-12-25 02:00",
"comments": null,
"createdAt": "2020-12-25T02:38:22.711Z",
"updatedAt": "2020-12-25T02:38:22.711Z",
"clientId": 1,
"employeeId": 1,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 7,
"start": "2020-12-25 00:15",
"end": "2020-12-25 03:00",
"comments": "treeeeee",
"createdAt": "2020-12-25T14:54:51.766Z",
"updatedAt": "2020-12-25T14:54:51.766Z",
"clientId": 1,
"employeeId": 1,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 8,
"start": "2020-12-25 04:00",
"end": "2020-12-25 06:00",
"comments": null,
"createdAt": "2020-12-25T15:02:54.737Z",
"updatedAt": "2020-12-25T15:02:54.737Z",
"clientId": 1,
"employeeId": 1,
"serviceId": null,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
},
{
"id": 12,
"start": "2020-12-31 19:30",
"end": "2020-12-31 21:00",
"comments": "Agora foi",
"createdAt": "2020-12-25T15:25:40.233Z",
"updatedAt": "2020-12-25T15:25:40.233Z",
"clientId": 1,
"employeeId": 1,
"serviceId": 1,
"appointmentStatusId": null,
"tenantId": 1,
"employee": {
"firstName": "Aline",
"lastName": "Magalhães"
},
"client": {
"firstName": "Tamires",
"lastName": "Almeida"
}
}
]
I need to present only some of this data in the V-Calendar vuetify and according to its documentation it would be for example:
{
name: 'name'
start: '0000-00-00 00:00'
end: '0000-00-00 00:00'
}
To reach this structure I have the following code snippet in my .Vue:
created () {
this.initialize()
},
methods: {
initialize () {
// request Events
axios.get('http://192.168.15.11:3000/events')
.then((response) => {
this.events = response.data
for (const item of this.events) {
const name = item.client.firstName + ' ' + item.client.lastName
const start = item.start
const end = item.end
const items = { name, start, end }
this.events = this.items
console.log(items);
}
})
.catch((error) => {
console.log(error.response);
})
},
My console gives this feedback with the right format I need but in the calendar there is no event:
The V-Calendar excerpt:
<v-calendar
ref="calendar"
v-model="focus"
color="primary"
locale="pt-br"
:events="events"
:event-color="getEventColor"
:type="type"
#click:event="showEvent"
#click:more="viewDay"
#click:date="viewDay"
>
</v-calendar>
data: () => ({
events []
}),
Where can I be wrong, could someone help me?
Great work on providing a good context for your problem. V-calendar wants events to be an array, not a single object.
Maybe try something like this:
this.events = [];
axios.get('http://192.168.15.11:3000/events')
.then((response) => {
const events = response.data
for (const item of events) {
const name = item.client.firstName + ' ' + item.client.lastName
const start = item.start
const end = item.end
this.events.push({ name, start, end })
}
})

extra bag information is missing in the flight offer price response

I'm testing self-service APIs. I wonder if this is a bug:
I make a search request, and the response contains the extra bag information in the flight-offer/price/additionalServices
Then I make the offer price request by adding include=bags parameter in the path of Flight Offers Price API.
However there is no any bags information in the response, neither in the offer/price/additionalServices, nor in the included/.
I still try to create order by adding the extra bag. So I use the extra bag information that I got at step 1 (search response). And the order is created successfully.
It seems that the extra bag information is missing in step 2 (response of flight offer price), is it a bug?
Here is an example of my test to reproduce the issue:
search request
{
"currencyCode": "EUR",
"originDestinations": [
{
"id": "1",
"originLocationCode": "PAR",
"destinationLocationCode": "NYC",
"departureDateTimeRange": {
"date": "2020-08-20",
"time": "10:00:00"
}
}
],
"travelers": [
{
"id": "1",
"travelerType": "ADULT"
}
],
"sources": [
"GDS"
],
"searchCriteria": {
"maxFlightOffers": 3
}
}
Then I select the second offer in the response to make a offer price request using include=bags parameter
{
"type": "flight-offer",
"id": "2",
"source": "GDS",
"instantTicketingRequired": false,
"nonHomogeneous": false,
"oneWay": false,
"lastTicketingDate": "2020-08-13",
"numberOfBookableSeats": 8,
"itineraries": [
{
"duration": "PT8H15M",
"segments": [
{
"departure": {
"iataCode": "ORY",
"terminal": "4",
"at": "2020-08-20T19:45:00"
},
"arrival": {
"iataCode": "EWR",
"terminal": "B",
"at": "2020-08-20T22:00:00"
},
"carrierCode": "TX",
"number": "6720",
"aircraft": {
"code": "359"
},
"operating": {
"carrierCode": "BF"
},
"duration": "PT8H15M",
"id": "3",
"numberOfStops": 0,
"blacklistedInEU": false
}
]
}
],
"price": {
"currency": "EUR",
"total": "149.44",
"base": "41.00",
"fees": [
{
"amount": "0.00",
"type": "SUPPLIER"
},
{
"amount": "0.00",
"type": "TICKETING"
}
],
"grandTotal": "149.44",
"additionalServices": [
{
"amount": "70.00",
"type": "CHECKED_BAGS"
}
]
},
"pricingOptions": {
"fareType": [
"PUBLISHED"
],
"includedCheckedBagsOnly": false
},
"validatingAirlineCodes": [
"TX"
],
"travelerPricings": [
{
"travelerId": "1",
"fareOption": "STANDARD",
"travelerType": "ADULT",
"price": {
"currency": "EUR",
"total": "149.44",
"base": "41.00"
},
"fareDetailsBySegment": [
{
"segmentId": "3",
"cabin": "ECONOMY",
"fareBasis": "ULBCOWFR",
"brandedFare": "EBASIC",
"class": "U",
"includedCheckedBags": {
"quantity": 0
}
}
]
}
]
}
There is no extra bag in the response.
Thanks

Transform Multiple rows of JSON format to SQL table

I have JSON file in Blob Storage that looks like this:
{
"Id": "****************************",
"Status": "OK",
"ProviderName": "Xero API Previewer",
"DateTimeUTC": "\/Date(1576561543598)\/",
"Invoices": [
{
"Type": "ACCPAY",
"InvoiceID": "*****************************",
"InvoiceNumber": "457489",
"Reference": "",
"Payments": [],
"CreditNotes": [],
"Prepayments": [],
"Overpayments": [],
"AmountDue": 0.00,
"AmountPaid": 0.00,
"AmountCredited": 0.00,
"CurrencyRate": 1.000000,
"IsDiscounted": false,
"HasAttachments": false,
"HasErrors": false,
"Contact": {
"ContactID": "************************************",
"Name": "********************",
"Addresses": [],
"Phones": [],
"ContactGroups": [],
"ContactPersons": [],
"HasValidationErrors": false
},
"DateString": "2102-11-26T00:00:00",
"Date": "\/Date(4193942400000+0000)\/",
"DueDateString": "2012-11-28T00:00:00",
"DueDate": "\/Date(1354060800000+0000)\/",
"Status": "VOIDED",
"LineAmountTypes": "Inclusive",
"LineItems": [
{
"Description": "Parking ",
"UnitAmount": 465.01,
"TaxType": "INPUT2",
"TaxAmount": 60.65,
"LineAmount": 465.01,
"AccountCode": "274",
"Tracking": [
{
"Name": "Region",
"Option": "New Zealand",
"TrackingCategoryID": "****************************************",
"Options": []
},
{
"Name": "Owner",
"Option": "Head Office",
"TrackingCategoryID": "***************************************",
"Options": []
}
],
"Quantity": 1.0000,
"LineItemID": "**************************************"
}
],
"SubTotal": 404.36,
"TotalTax": 60.65,
"Total": 465.01,
"UpdatedDateUTC": "\/Date(1355876228590+0000)\/",
"CurrencyCode": "NZD"
},
{
"Type": "ACCPAY",
"InvoiceID": "**************************************",
"InvoiceNumber": "176295-01",
"Reference": "",
"Payments": [
{
"PaymentID": "********************************************",
"Date": "\/Date(1576454400000+0000)\/",
"Amount": 137.43,
"Reference": "",
"CurrencyRate": 1.000000,
"HasAccount": false,
"HasValidationErrors": false
}
],
"CreditNotes": [],
"Prepayments": [],
"Overpayments": [],
"AmountDue": 0.00,
"AmountPaid": 137.43,
"AmountCredited": 0.00,
"CurrencyRate": 1.000000,
"IsDiscounted": false,
"HasAttachments": true,
"HasErrors": false,
"Contact": {
"ContactID": "************************************",
"Name": "InkWorks",
"Addresses": [],
"Phones": [],
"ContactGroups": [],
"ContactPersons": [],
"HasValidationErrors": false
},
"DateString": "2019-12-17T00:00:00",
"Date": "\/Date(1576540800000+0000)\/",
"DueDateString": "2020-01-20T00:00:00",
"DueDate": "\/Date(1579478400000+0000)\/",
"Status": "PAID",
"LineAmountTypes": "Inclusive",
"LineItems": [
{
"Description": "general stationery",
"UnitAmount": 137.43,
"TaxType": "INPUT2",
"TaxAmount": 17.93,
"LineAmount": 137.43,
"AccountCode": "273",
"Tracking": [
{
"Name": "Owner",
"Option": "Head Office",
"TrackingCategoryID": "******************************",
"Options": []
}
],
"Quantity": 1.0000,
"LineItemID": "****************************************"
}
],
"SubTotal": 119.50,
"TotalTax": 17.93,
"Total": 137.43,
"UpdatedDateUTC": "\/Date(1576524509820+0000)\/",
"CurrencyCode": "NZD",
"FullyPaidOnDate": "\/Date(1576454400000+0000)\/"
},
I want to store LineItems into a Table with columns as follows:
InvoiceID LineItemID Description LineAmount AccountCode Date
There can be multiple LineItems in a single invoice.
I managed to get the top level only with the following code.
WITH cte AS (
SELECT CAST (BulkColumn AS NVARCHAR(MAX)) AS jsonData
FROM
OPENROWSET(
BULK 'temp/XeroJson.json',
DATA_SOURCE = 'test'
-- FORMATFILE_DATA_SOURCE = 'test'
, SINGLE_CLOB
) AS blob
)
SELECT *
FROM cte
CROSS APPLY
OPENJSON(cte.jsonData) j
How can I make this work?
This is my test .json file, I placed it in my storage account :
{
"Id": "****************************",
"Status": "OK",
"ProviderName": "Xero API Previewer",
"DateTimeUTC": "\/Date(1576561543598)\/",
"Invoices":
[
{
"Type": "ACCPAY",
"InvoiceID": "123456",
"InvoiceNumber": "457489",
"Reference": "",
"Payments": [],
"CreditNotes": [],
"Prepayments": [],
"Overpayments": [],
"AmountDue": 0.00,
"AmountPaid": 0.00,
"AmountCredited": 0.00,
"CurrencyRate": 1.000000,
"IsDiscounted": false,
"HasAttachments": false,
"HasErrors": false,
"Contact": {
"ContactID": "************************************",
"Name": "********************",
"Addresses": [],
"Phones": [],
"ContactGroups": [],
"ContactPersons": [],
"HasValidationErrors": false
},
"DateString": "2102-11-26T00:00:00",
"Date": "\/Date(4193942400000+0000)\/",
"DueDateString": "2012-11-28T00:00:00",
"DueDate": "\/Date(1354060800000+0000)\/",
"Status": "VOIDED",
"LineAmountTypes": "Inclusive",
"LineItems": [{
"Description": "Parking ",
"UnitAmount": 465.01,
"TaxType": "INPUT2",
"TaxAmount": 60.65,
"LineAmount": 465.01,
"AccountCode": "274",
"Tracking": [{
"Name": "Region",
"Option": "New Zealand",
"TrackingCategoryID": "****************************************",
"Options": []
}, {
"Name": "Owner",
"Option": "Head Office",
"TrackingCategoryID": "***************************************",
"Options": []
}
],
"Quantity": 1.0000,
"LineItemID": "**************************************"
},
{
"Description": "Parking2 ",
"UnitAmount": 111.11,
"TaxType": "INPUT2",
"TaxAmount": 60.65,
"LineAmount": 465.01,
"AccountCode": "276",
"Tracking": [{
"Name": "Region",
"Option": "New Zealand",
"TrackingCategoryID": "****************************************",
"Options": []
}, {
"Name": "Owner",
"Option": "Head Office",
"TrackingCategoryID": "***************************************",
"Options": []
}
],
"Quantity": 1.0000,
"LineItemID": "**************************************"
}
],
"SubTotal": 404.36,
"TotalTax": 60.65,
"Total": 465.01,
"UpdatedDateUTC": "\/Date(1355876228590+0000)\/",
"CurrencyCode": "NZD"
},
{
"Type": "ACCPAY",
"InvoiceID": "1234567",
"InvoiceNumber": "176295-01",
"Reference": "",
"Payments": [{
"PaymentID": "********************************************",
"Date": "\/Date(1576454400000+0000)\/",
"Amount": 137.43,
"Reference": "",
"CurrencyRate": 1.000000,
"HasAccount": false,
"HasValidationErrors": false
}
],
"CreditNotes": [],
"Prepayments": [],
"Overpayments": [],
"AmountDue": 0.00,
"AmountPaid": 137.43,
"AmountCredited": 0.00,
"CurrencyRate": 1.000000,
"IsDiscounted": false,
"HasAttachments": true,
"HasErrors": false,
"Contact": {
"ContactID": "************************************",
"Name": "InkWorks",
"Addresses": [],
"Phones": [],
"ContactGroups": [],
"ContactPersons": [],
"HasValidationErrors": false
},
"DateString": "2019-12-17T00:00:00",
"Date": "\/Date(1576540800000+0000)\/",
"DueDateString": "2020-01-20T00:00:00",
"DueDate": "\/Date(1579478400000+0000)\/",
"Status": "PAID",
"LineAmountTypes": "Inclusive",
"LineItems": [{
"Description": "general stationery",
"UnitAmount": 137.43,
"TaxType": "INPUT2",
"TaxAmount": 17.93,
"LineAmount": 137.43,
"AccountCode": "273",
"Tracking": [{
"Name": "Owner",
"Option": "Head Office",
"TrackingCategoryID": "******************************",
"Options": []
}
],
"Quantity": 1.0000,
"LineItemID": "****************************************"
}
],
"SubTotal": 119.50,
"TotalTax": 17.93,
"Total": 137.43,
"UpdatedDateUTC": "\/Date(1576524509820+0000)\/",
"CurrencyCode": "NZD",
"FullyPaidOnDate": "\/Date(1576454400000+0000)\/"
}
]
}
As you can see the first invoice has two lineItems for demo here.
This is my sql script to exract from the json from storage :
CREATE DATABASE SCOPED CREDENTIAL AccessAzureInvoices
WITH
IDENTITY = 'SHARED ACCESS SIGNATURE'
-- REMOVE ? FROM THE BEGINNING OF THE SAS TOKEN
, SECRET = '<YOUR STORAGE SAS TOKEN>'
;
CREATE EXTERNAL DATA SOURCE MyAzureInvoices
WITH
( LOCATION = 'https://<YOUR STORAGE NAME>.blob.core.windows.net/<CONTAINER NAME WHERE YOUR JSON FILE IN>'
, CREDENTIAL = AccessAzureInvoices
, TYPE = BLOB_STORAGE
)
;
DECLARE #jsonVariable NVARCHAR(MAX);
set #jsonVariable = (select * from OPENROWSET(
BULK '<YOUR JSON FILE NAME>.json',
DATA_SOURCE = 'MyAzureInvoices',
SINGLE_CLOB
) AS blob)
select * from (
SELECT *
FROM OPENJSON(#jsonVariable,N'$.Invoices') WITH (
InvoiceID VARCHAR(200) N'$.InvoiceID',
Date VARCHAR(200) N'$.Date',
LineItems NVARCHAR(MAX) N'$.LineItems' as json
))as table1
CROSS APPLY OPENJSON(LineItems) with (
LineAmount VARCHAR(200) '$.LineAmount',
AccountCode VARCHAR(200)'$.AccountCode',
LineItemID VARCHAR(200) '$.LineItemID',
Description VARCHAR(200) '$.Description'
)
Result :
Hope it helps !

Using enums with AJV's "select/selectCases" keyword

Is it possible to give select a schema to match the case on?
The use case I have is that I want to select and match on a list of accepted values:
{
"type": "object",
"properties": {
"addressCountry": {
"type": ["string", "null"]
}
},
"select": {
"$data": "0/addressCountry"
},
"selectIf": {
"type": "string",
"enum": ["FR", "JP", "US", "NZ", "DE"]
},
"selectThen": {
"addressCountry": {
"type": "string"
}
}
}
EDIT: please note that selectIf and selectThen aren't keywords supported by AJV. It does support selectCases and selectDefault, however with selectCases you have to state each case individually. My question is more about if it's possible to match on multiple cases and use a single definition.
#Relequestual managed to help me solve this outside of SO. I didn't need to use select at all, could just use if/then/else like so:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"contactByPost": {
"type": "boolean"
},
"streetAddress1": {
"type": ["string", "null"]
},
"streetAddress2": {
"type": ["string", "null"]
},
"streetAddress3": {
"type": ["string", "null"]
},
"locality": {
"type": ["string", "null"]
},
"region": {
"type": ["string", "null"]
},
"postCode": {
"type": ["string", "number", "null"]
},
"country": {
"type": ["string", "null"]
}
},
"if": {
"type": "object",
"properties": {
"contactByPost": {
"type": "boolean",
"const": true
}
}
},
"then": {
"if": {
"type": "object",
"properties": {
"country": {
"type": "string",
"enum": ["JP", "US"]
}
}
},
"then": {
"type": "object",
"properties": {
"contactByPost": { "type": "boolean" },
"streetAddress1": { "type": "string" },
"locality": { "type": "string" },
"region": { "type": "string" },
"postCode": { "type": ["string", "number"] },
"country": { "type": "string" }
},
"required": ["streetAddress1", "locality", "region", "postCode", "country"]
},
"else": {
"type": "object",
"properties": {
"contactByPost": { "type": "boolean" },
"streetAddress1": { "type": "string" },
"locality": { "type": "string" },
"region": { "type": ["string", "null"] },
"country": { "type": "string" }
},
"required": ["streetAddress1", "locality", "country"]
}
}
}
Would provide the following results:
// Valid
{
"contactByPost": false
}
{
"contactByPost": true,
"streetAddress1": "123 Alphabet St",
"streetAddress2": null,
"streetAddress3": null,
"locality": "City",
"region": "State",
"postCode": "12345",
"country": "JP"
}
{
"contactByPost": true,
"streetAddress1": "123 Alphabet St",
"streetAddress2": null,
"streetAddress3": null,
"locality": "City",
"region": "State",
"postCode": "12345",
"country": "US"
}
{
"contactByPost": true,
"streetAddress1": "123 Alphabet St",
"streetAddress2": null,
"streetAddress3": null,
"locality": "City",
"region": "State",
"postCode": "12345",
"country": "NZ"
}
{
"contactByPost": true,
"streetAddress1": "123 Alphabet St",
"streetAddress2": null,
"streetAddress3": null,
"locality": "City",
"region": null,
"postCode": null,
"country": "NZ"
}
// Invalid
{
"contactByPost": true
}
{
"contactByPost": true,
"streetAddress1": "123 Alphabet St",
"streetAddress2": null,
"streetAddress3": null,
"locality": "City",
"region": null,
"postCode": null,
"country": "JP"
}
{
"contactByPost": true,
"streetAddress1": "123 Alphabet St",
"streetAddress2": null,
"streetAddress3": null,
"locality": "City",
"region": null,
"postCode": null,
"country": "US"
}