How to import JSON into SQL 2016 - sql-server

I'm trying something new and could use some guidance. I have a JSON file full of data that I would like to have imported into SQL 2016. I can get the entire file into SQL but breaking it apart into a readable format is where I am stuck. I'm new to SQL, so when reading articles on this subject I am struggling to comprehend. The following query is what I've used to perform the initial import:
SELECT *
FROM OPENROWSET (BULK 'c:\tmp\test.json', SINGLE_CLOB) as j
CROSS APPLY OPENJSON(BulkColumn)
Each row is populated but the values contain sub sections that I need to have expanded. Here is the test data that I am using:
{
"site_id":123456,
"statusEnum":"fully_configured",
"status":"fully-configured",
"domain":"site.name.com",
"account_id":111111,
"acceleration_level":"standard",
"site_creation_date":1410815844000,
"ips":[
"99.99.99.99"
],
"dns":[
{
"dns_record_name":"site.name.com",
"set_type_to":"CNAME",
"set_data_to":[
"frgt.x.wafdns.net"
]
}
],
"original_dns":[
{
"dns_record_name":"name.com",
"set_type_to":"A",
"set_data_to":[
""
]
},
{
"dns_record_name":"site.name.com",
"set_type_to":"A",
"set_data_to":[
"99.99.99.99"
]
},
{
"dns_record_name":"site.name.com",
"set_type_to":"CNAME",
"set_data_to":[
""
]
}
],
"warnings":[
],
"active":"active",
"additionalErrors":[
],
"display_name":"site.name.com",
"security":{
"waf":{
"rules":[
{
"action":"api.threats.action.block_ip",
"action_text":"Block IP",
"id":"api.threats.sql_injection",
"name":"SQL Injection"
},
{
"action":"api.threats.action.block_request",
"action_text":"Block Request",
"id":"api.threats.cross_site_scripting",
"name":"Cross Site Scripting"
},
{
"action":"api.threats.action.block_ip",
"action_text":"Block IP",
"id":"api.threats.illegal_resource_access",
"name":"Illegal Resource Access"
},
{
"block_bad_bots":true,
"challenge_suspected_bots":true,
"exceptions":[
{
"values":[
{
"ips":[
"99.99.99.99"
],
"id":"api.rule_exception_type.client_ip",
"name":"IP"
}
],
"id":123456789
},
{
"values":[
{
"ips":[
"99.99.99.99"
],
"id":"api.rule_exception_type.client_ip",
"name":"IP"
}
],
"id":987654321
}
],
"id":"api.threats.bot_access_control",
"name":"Bot Access Control"
},
{
"activation_mode":"api.threats.ddos.activation_mode.auto",
"activation_mode_text":"Auto",
"ddos_traffic_threshold":1000,
"id":"api.threats.ddos",
"name":"DDoS"
},
{
"action":"api.threats.action.quarantine_url",
"action_text":"Auto-Quarantine",
"id":"api.threats.backdoor",
"name":"Backdoor Protect"
},
{
"action":"api.threats.action.block_ip",
"action_text":"Block IP",
"id":"api.threats.remote_file_inclusion",
"name":"Remote File Inclusion"
},
{
"action":"api.threats.action.disabled",
"action_text":"Ignore",
"id":"api.threats.customRule",
"name":"wafRules"
}
]
},
"acls":{
"rules":[
{
"ips":[
"99.99.99.99"
],
"id":"api.acl.whitelisted_ips",
"name":"Visitors from whitelisted IPs"
},
{
"geo":{
"countries":[
"BR",
"CN",
"DE",
"ES",
"GB",
"HK",
"IR",
"IT",
"KP",
"KR",
"KZ",
"NL",
"PL",
"RO",
"RU",
"TR",
"TW",
"UA"
]
},
"id":"api.acl.blacklisted_countries",
"name":"Visitors from blacklisted Countries"
}
]
}
},
"sealLocation":{
"id":"api.seal_location.none",
"name":"No seal "
},
"ssl":{
"origin_server":{
"detected":true,
"detectionStatus":"ok"
},
"generated_certificate":{
"ca":"GS",
"validation_method":"email",
"validation_data":"administrator#site.name.com",
"san":[
"*.site.name.com"
],
"validation_status":"done"
}
},
"siteDualFactorSettings":{
"specificUsers":[
],
"enabled":false,
"customAreas":[
],
"allowAllUsers":true,
"shouldSuggestApplicatons":true,
"allowedMedia":[
"ga",
"sms"
],
"shouldSendLoginNotifications":true,
"version":0
},
"login_protect":{
"enabled":false,
"specific_users_list":[
],
"send_lp_notifications":true,
"allow_all_users":true,
"authentication_methods":[
"ga",
"sms"
],
"urls":[
],
"url_patterns":[
]
},
"performance_configuration":{
"advanced_caching_rules":{
"never_cache_resources":[
],
"always_cache_resources":[
]
},
"acceleration_level":"standard",
"async_validation":true,
"minify_javascript":true,
"minify_css":true,
"minify_static_html":true,
"compress_jepg":true,
"progressive_image_rendering":false,
"aggressive_compression":false,
"compress_png":true,
"on_the_fly_compression":true,
"tcp_pre_pooling":true,
"comply_no_cache":false,
"comply_vary":false,
"use_shortest_caching":false,
"perfer_last_modified":false,
"accelerate_https":false,
"disable_client_side_caching":false,
"cache300x":false,
"cache_headers":[
]
},
"extended_ddos":1000,
"res":0,
"res_message":"OK",
"debug_info":{
"id-info":"1234"
}
}
I know enough about SQL to know that I am going to have to have multiple tables for these subsections. How do I select these subsections to expand them out into their own tables? If I am not clear on the explanation or the question, please comment and I will do my best to be more precise.

I was able to successfully import my JSON data into a SQL data base using the following code:
###Getting the list of Site_IDs
$param1 = #{account_id='####';api_id='######'; api_key='asdfjklmnopqrstuvwxyz';page_size='1000'}
$sitelist = Invoke-WebRequest https://my.website.com/api/prov/v1/sites/list -Method Post -Body $param1
$sitelist = $sitelist.content
$sitelist = $sitelist | convertfrom-json
$sitelist = $sitelist.sites
$sites = $sitelist | select -ExpandProperty Site_ID
###Setting the ConnectionString for the SQL Server and Database
$server = 'servername\sqlinstance'
$database = 'databasename'
$connstring = "server = $server; database = $database; trusted_connection = true;"
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = $connstring
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.CommandTimeout = 60
$cmd.Connection = $conn
$cmd.CommandText = $query
$cmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("#Site_ID",[Data.SQLDBType]::BigInt,20))) | Out-Null
$cmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("#JSON_Source",[Data.SQLDBType]::NVARCHAR))) | Out-Null
###Setting the SQL Query to Insert the Site Data
$query = #"
INSERT INTO dbo.WebsiteSourceData (Site_ID,JSON_Source)
Values (#Site_ID, #JSON_Source);
"#
###Opening the SQL Connection
Try{
$conn.Open()
###Looping through each site to get it's configuration and then inserting that data to SQL
ForEach($site in $sites){
$param2 = #{api_id='#####';api_key='abcdefghijklmnopqrstuvwxyz';site_id="$site"}
$status = Invoke-WebRequest -URI https://my.website.com/api/prov/v1/sites/status -Method Post -Body $param2
$content = $status.Content
$adapter = New-Object System.Data.SqlClient.SqlDataAdapter
$adapter.SelectCommand = $cmd
$cmd.Parameters[0].Value = $site
$cmd.Parameters[1].Value = $content
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataset)
}#ForEach($site in $sites)
}#Try
Catch{
Write-Host "Exception thrown : $($error[0].exception.message)"
}#Catch
Finally{
$conn.Close()
}#Finally
From there, using the extremely helpful advice from this thread: How to shred JSON data from within a SQL database I was able to access and parse out the data into separate tables.

Related

Powershell JSON : How to retrieve specific key-value pair for all array items

I am trying to get the list of "enabled" features from featureset array from below JSON snippet with powershell.
output expected :
feature1, feature2, feature4
I tried this piece of code but I was only able to get to the specific index of the array, not all elements, also not able to put condition for "enable" = true :
$output = foreach( $feature in $jsn.abc.comp1.featureset[0].psobject.Properties ) {
[PSCustomObject]#{
featureName = $feature.Name
featureValue = $feature.Value
}
}
json:
{
"abc": {
"comp1": {
"id": "1308",
"featureset":[
{
"name": "feature1",
"enable" : true,
"ID": "0670FF495355878281174937"
},
{
"name": "feature2",
"enable" : true,
"ID": "0670FF495355878281174937"
},
{
"name": "feature3",
"enable" : false,
"ID": "0670FF495355878281174937"
},
{
"name": "feature4",
"enable" : true,
"ID": "0670FF495355878281174937"
}
]
}
}
}
Loop over the whole featureset array, use Where-Object to filter:
$output = $jsn.abc.comp1.featureset |Where-Object enable -eq $true |ForEach-Object {
$_.Name
}

How to add objects to a blank array in a json file using powershell

here is my json body .
{
"source": 2,
"revision": 3,
"description": null,
"triggers": [],
"releaseNameFormat": "Release-$(rev:r)",
"tags": [],
"pipelineProcess": {
"type": 1
},
"properties": {
"DefinitionCreationSource": {
"$type": "System.String",
"$value": "BuildSummary"
},
"System.EnvironmentRankLogicVersion": {
"$type": "System.String",
"$value": "2"
}
},
"id": 5,
"name": "CheckListAPI - CD",
"path": "\\Admin",
"projectReference": null,
"url": "",
"_links": {
"self": {
"href": ""
},
"web": {
"href": ""
}
}
}
I want to add some values inside the brackets at "triggers": [],
What I'm trying to get is:
"triggers":
[
{
"artifactAlias": "_DV_NJ_PIPE",
"triggerConditions": [],
"triggerType": 1
}
],
i tried -replace and replace() saving the json file to local system, but none of them are working, I even tried to edit the json file directly like this but failed.
$alias = $json.triggers
foreach ($artifact in $alias )
{
$artifact.artifactAlias = "_$DefName"
$artifact.triggerConditions = "{}"
$artifact.triggertype = "artifactSource"
}
Please help.
You can import the json file as PowerShell objects, manipulate the structure until it looks the way you want it to and export it back to json format:
$pipeline = Get-Content .\input.json | ConvertFrom-Json
$trigger = [ordered]#{
artifactAlias = "_DV_NJ_PIPE"
triggerConditions = #()
triggerType = 1
}
$pipeline.triggers += $trigger
$pipeline | ConvertTo-Json -Depth 5 | Out-File .\output.json
As it was pointed out in the comments, it is of course also possible to import the trigger definition from a json file instead of building it in a hash table.

Replace symbol in JSON with different array values

I have 2 files
text.json that contains
{
"Files": [
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
}
]
}
and dlls.txt
1.dll
2.dll
..
6.dll
I want to replace the symbol * with the necessary dll like this :
"Files": [
{
"pattern": "/Something/Something/1.dll"
},
{
"pattern": "/Something/Something/2.dll"
},
.
.
.
{
"pattern": "/Something/Something/6.dll"
}
]
}
So far my code replaces the symbol but only with the last array element.
Since you're dealing with a structured data format - JSON - using a dedicated parser is always preferable to performing purely textual processing based on regexes.
While using the dedicated ConvertFrom-Json and ConvertTo-Json cmdlets to parse from and serialize back to JSON is slower than textual processing, it is much more robust.
# Read the DLL names from the text file into an array of strings.
$dlls = Get-Content dlls.txt
# Read the JSON file and parse it into an object.
$objFromJson = Get-Content -Raw text.json | ConvertFrom-Json
# Loop over all elements of the array in the .Files property and
# update their .pattern property based on the corresponding DLL names.
$i = 0
$objFromJson.Files.ForEach({
$_.pattern = $_.pattern -replace '(?<=/)\*$', $dlls[$i++]
})
# Convert the updated object back to JSON; save to a file as needed.
$objFromJson | ConvertTo-Json
Why not skip the 'C:\Users\itsan\Desktop\text.json' file alltogether and simply create a new JSON from the dll filenames you have in 'C:\Users\itsan\Desktop\dlls.txt' ?
$dlls = Get-Content -Path 'C:\Users\itsan\Desktop\dlls.txt'
$result = [PsCustomObject]#{
Files = foreach($file in $dlls) {
"" | Select-Object #{Name = 'pattern'; Expression = {"/Something/Something/$file"}}
}
}
$result | ConvertTo-Json
If you want that as new file, simply change the last line into
$result | ConvertTo-Json | Set-Content -Path 'C:\Users\itsan\Desktop\dll.json'
Output wil be like this:
{
"Files": [
{
"pattern": "/Something/Something/1.dll"
},
{
"pattern": "/Something/Something/2.dll"
},
{
"pattern": "/Something/Something/3.dll"
},
{
"pattern": "/Something/Something/4.dll"
},
{
"pattern": "/Something/Something/5.dll"
},
{
"pattern": "/Something/Something/6.dll"
}
]
}

Laravel how to return object into JSON Arrays data type without keys

I have DB query in the Controller like this:
$query = User::all('id','name','email')->take(2);
$users = ["data" => $query];
return $users;
And get the result:
{
"data": [
{
"id": 1,
"name": "Peter",
"email": "peter#peter.com"
},
{
"id": 2,
"name": "John",
"email": "john#john.com"
}
]
}
But i'm expecting to get JSON Arrays data type without keys like this:
{
"data": [
[
"1",
"Peter",
"peter#peter.com"
],
[
"2",
"John",
"john#john.com"
]
]
}
I need to get this type for DataTables JSONP data source for remote domains.
https://datatables.net/examples/server_side/jsonp.html
How to do this?
Thanks.
You can try array_values like so:
$query = User::all('id', 'name', 'email')->take(2);
$users = ["data" => $query->map(function (User $user) {
return array_values($user->attributesToArray());
})];
return $users;
How about something like this?
$query = User::all('id', 'name', 'email')->take(2);
$userValues = $query->map(function($item, $key) {
return [
$item['id'],
$item['name'],
$item['email']
];
})
$users = ["data" => $userValues];
return $users;
// result
{
"data": [
[
1,
"Amy Wilderman",
"vrau#example.net",
],
[
2,
"Bria Lindgren PhD",
"trevor.armstrong#example.org",
],
]
}

How to add an object in array on parsed JSON?

I have this file .json:
{
"topologyTypes": {
"stations": {
"instances": [
{
"#name": "value1",
"#address": "value2"
},
{
"#name": "value3",
"#address": "value4"
}
]
}
},
"agg": {},
"inter": {}
}
I want to add an object like this in topologyType.stations.instances with PowerShell
{
"#name": "value4",
"#adress": "value5"
}
So I tried this following code in PowerShell, but it doesn't work:
$path = "./data.json"
$jsonFile = Get-Content $path -Raw | ConvertFrom-Json
$jsonContent = #"
{
"#name": "value4",
"#adress": "value5"
}
"#
$jsonFile.topologyTypes.stations.instances |
Add-Content -Value (ConvertFrom-Json $jsonContent)
The desired output I would like to get is like this:
{
"topologyTypes": {
"stations": {
"instances": [
{
"#name": "value1",
"#address": "value2"
},
{
"#name": "value3",
"#address": "value4"
},
{
"#name": "value4",
"#address": "value5"
}
]
}
},
"agg": {},
"inter": {}
}
Define the new content as a PowerShell custom object:
$jsonContent = [PSCustomObject]#{
'#name' = 'value4'
'#adress' = 'value5'
}
append it to the instances substructure of your imported JSON data:
$jsonFile.topologyTypes.stations.instances += $jsonContent
then convert the data back to a JSON string:
$jsonFile | ConvertTo-Json -Depth 4
Note that ConvertTo-Json inserts a lot of intention space. If you want exactly the format you posted you need to do some pretty-printing yourself. Something like this might help.

Resources