Create a specific json(Hash) from a csv using Ruby - arrays

I would appreciate any help trying to create a multi faceted CSV (with header) into a json I can use for a post. Here is csv and JSON format required. Ultimately; I need to create a single location that may have 1, 2, or many fax machines.
csv
ID,Location Name,timezone,code,display,address,city,state,postalcode,country,faxlocation,faxnumber,(in)active
5,Location1,America/Chicago,bu,Building,1313 Mocking Bird Lane,The City,IL,999999,USA,Room 1; Room 2,111111111; 2222222222,active
8,Location2,America/New_York,bu,Building,2626 Humpty Dumpty Lane,Another City,NY,999999,USA,Room 1; Room 2; Room 3,111111111; 2222222222; 3333333333,active
32,Location3,America/Los_Angeles,bu,Building,3939 Big Bird Lane,Last City,CA,999999,USA,Room 1,111111111,active
json
{
"resourceType": "Location",
"id": "5",
"description": "America/Chicago",
"name": "Location1",
"address": {
"address": "1313 Mocking Bird Lane",
"city": "The City",
"state": "IL",
"postalCode": "999999",
"country": "USA"
},
"telecom": [
{
"system": "fax",
"value": "1111111111",
"use": "work",
"extension": [
{
"url": "displayValue",
"valueString": "Room 1"
}
]
},
{
"system": "fax",
"value": "2222222222",
"use": "work",
"extension": [
{
"url": "displayValue",
"valueString": "Room "
}
]
}
],
"status": "active"
}
all requires here
locations = CSV.read(csv)
locations.shift # remove header row
locations.each_index do |index|
faxnumarrat = locations[index][10].to_s.delete(' ').split(';') #Take 10th index and turn it into an array
faxlocarray = locations[index][11].to_s.delete(' ').split(';') #Take 11th index and turn it into an array
# keys = ['loc1','loc2']
# values = ['fax1','fax2']
my_hash = Hash[faxnumarray.zip(faxlocarray)] # Combine locations and fax numbers
my_hash.each do |key, value|
#fax_hash = { 'system' => 'fax', 'value' => key, 'use' => 'work', 'extension' => [{ 'url' => 'automaticSend', 'valueBoolean' => false }, { 'url' => 'displayValue', 'valueString' => value }] } #Build up a hash using k,v. ISSUE: Only creates one fax. Need to put all faxes associated no matter how many per location
end
end

Instead of reading in the entire CSV as an array of arrays, you instead can open
or create a new CSV instance and pass in an option to convert the first line of
into headers into keys to access columns within a row more easily; e.g.
locations = CSV.open(csv, headers: true)
location = locations.first
# => #<CSV::Row "ID":"5" "Location Name":"Location1" "timezone":"America/Chicago" "code":"bu" "display":"Building" "address":"1313 Mocking Bird Lane" "city":"The City" "state":"IL" "postalcode":"999999" "country":"USA" "faxlocation":"Room 1; Room 2" "faxnumber":"111111111; 2222222222" "(in)active":"active">
location["Location Name"]
# => "Location1"
With the headers as keys we can use, we can then build a new Hash object using
those old values, whilst also build a collection they you had started in your
question example
locations = CSV.open(csv, headers: true)
results = locations.map.with_index do |location, index|
faxnumarray = location["faxnumber"].delete(' ').split(';') #Take 10th index and turn it into an array
faxlocarray = location["faxlocation"].delete(' ').split(';') #Take 11th index and turn it into an array
# keys = ['loc1','loc2']
# values = ['fax1','fax2']
my_hash = Hash[faxnumarray.zip(faxlocarray)] # Combine locations and fax numbers
{
"resourceType" => "Location",
"id" => location["ID"],
"description" => location["timezone"],
"name" => location["Location Name"],
"address" => {
"address" => location["address"],
"city" => location["city"],
"state" => location["state"],
"postalCode" => location["postalcode"],
"country" => location["country"]
},
"telecom" => my_hash.map do |key, value|
{
'system' => 'fax',
'value' => key,
'use' => 'work',
'extension' => [
{
'url' => 'automaticSend',
'valueBoolean' => false
},
{
'url' => 'displayValue',
'valueString' => value
}
]
}
end,
"status" => location["(in)active"]
}
end
results.to_json
I reused your code where I could and made the last object (the returned object)
within the map block resemble the requested Hash result object. Using map
instead of each means it
Returns a new array with the results of running block once for every element in enum.
-- Module: Enumerable (Ruby 2_4_0)
This produces the following result
[
{
"resourceType": "Location",
"id": "5",
"description": "America/Chicago",
"name": "Location1",
"address": {
"address": "1313 Mocking Bird Lane",
"city": "The City",
"state": "IL",
"postalCode": "999999",
"country": "USA"
},
"telecom": [
{
"system": "fax",
"value": "111111111",
"use": "work",
"extension": [
{
"url": "automaticSend",
"valueBoolean": false
},
{
"url": "displayValue",
"valueString": "Room 1"
}
]
},
{
"system": "fax",
"value": "2222222222",
"use": "work",
"extension": [
{
"url": "automaticSend",
"valueBoolean": false
},
{
"url": "displayValue",
"valueString": " Room 2"
}
]
}
],
"status": "active"
},
{
"resourceType": "Location",
"id": "8",
"description": "America/New_York",
"name": "Location2",
"address": {
"address": "2626 Humpty Dumpty Lane",
"city": "Another City",
"state": "NY",
"postalCode": "999999",
"country": "USA"
},
"telecom": [
{
"system": "fax",
"value": "111111111",
"use": "work",
"extension": [
{
"url": "automaticSend",
"valueBoolean": false
},
{
"url": "displayValue",
"valueString": "Room 1"
}
]
},
{
"system": "fax",
"value": "2222222222",
"use": "work",
"extension": [
{
"url": "automaticSend",
"valueBoolean": false
},
{
"url": "displayValue",
"valueString": " Room 2"
}
]
},
{
"system": "fax",
"value": "3333333333",
"use": "work",
"extension": [
{
"url": "automaticSend",
"valueBoolean": false
},
{
"url": "displayValue",
"valueString": " Room 3"
}
]
}
],
"status": "active"
},
{
"resourceType": "Location",
"id": "32",
"description": "America/Los_Angeles",
"name": "Location3",
"address": {
"address": "3939 Big Bird Lane",
"city": "Last City",
"state": "CA",
"postalCode": "999999",
"country": "USA"
},
"telecom": [
{
"system": "fax",
"value": "111111111",
"use": "work",
"extension": [
{
"url": "automaticSend",
"valueBoolean": false
},
{
"url": "displayValue",
"valueString": "Room 1"
}
]
}
],
"status": "active"
}
]
References:
Class: CSV (Ruby 2_4_0)

Related

JSON Schema: Check the array to validate if a certain block of JSON objects is contained in it

I have a JSON array of arbitrary length. Each item in the array is a nested block of JSON objects, they all have same properties but different values.
I need a JSON schema to check the array if the last block in the array has the values defined in the schema.
How should the scheme be defined so that it only considers the last block in the array and ignores all the blocks before in the array?
My current solution successfully validates the JSON objects if there is only one block in the array. As soon as I have more blocks, it fails because all the others are not valid against my schema - for sure, this corresponds to the expected behaviour.
In my example, the JSON array contains two nested blocks of JSON objects. These differ for the following items:
event.action = "[load|button]"
event.label = "[journey:device-only|submit,journey:device-only]"
type = "[page|track]"
An example for my data are:
[
{
"page": {
"path": "order/checkout/summary",
"language": "en"
},
"cart": {
"ordercase": "neworder",
"product_list": [
{
"name": "Apple iPhone 14 Plus",
"quantity": 1,
"price": 1000
}
]
},
"event": {
"action": "load",
"label": "journey:device-only"
},
"type": "page"
},
{
"page": {
"path": "order/checkout/summary",
"language": "en"
},
"cart": {
"ordercase": "neworder",
"product_list": [
{
"name": "Apple iPhone 14 Plus",
"quantity": 1,
"price": 1000
}
]
},
"event": {
"action": "button",
"label": "submit,journey:device-only",
},
"type": "track"
}
]
And the schema I use which works fine for the second block if the block would be the only one in the array:
{
"type": "array",
"$schema": "http://json-schema.org/draft-07/schema#",
"items": {
"type": "object",
"required": ["event", "page", "type"],
"properties": {
"page": {
"type": "object",
"properties": {
"path": {
"const": "order/checkout/summary"
},
"language": {
"enum": ["de", "fr", "it", "en"]
}
},
"required": ["path", "language"]
},
"event": {
"type": "object",
"additionalProperties": false,
"properties": {
"action": {
"const": "button"
},
"label": {
"type": "string",
"pattern": "^[-_:, a-z0-9]*$",
"allOf": [
{
"type": "string",
"pattern": "^\\S*(?:(submit,|,submit))\\S*$"
},
{
"type": "string",
"pattern": "^\\S*(journey:(?:(device-only|device-plus)))\\S*$"
}
]
}
},
"required": ["action", "label"]
},
"type": {
"enum": ["track", "string"]
}
}
}
}

JSON-schema object array validation

I have a mission to validate such a JSON message :
{
"header": {
"action": "change_time",
"taskGuid": "someTaskGuid",
"publishDate": "2012-04-23T18:25:43.511Z"
},
"data": {
"code": "f2103839",
"conditions": [
{
"conditionsType": "A",
"dateBegin": "2021-11-22T17:30:43.511Z",
"dateEnd": "2021-11-22T17:35:43.511Z"
},
{
"conditionsType": "B",
"dateBegin": "2021-11-22T17:30:43.511Z",
"dateEnd": "2021-11-22T17:35:43.511Z"
},
{
"conditionsType": "C",
"dateBegin": "2021-11-22T17:30:43.511Z",
"dateEnd": "2021-11-22T17:35:43.511Z"
}
]
}
}
I've made such a JSON-schema to achieve that :
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "Some schema",
"description": "Some schema",
"type": "object",
"required": [
"header",
"data"
],
"properties": {
"header": {
"type": "object",
"required": [
"action",
"taskGuid",
"publishDate"
],
"properties": {
"action": {
"enum": [
"create_work_order",
"change_time",
"cancel_work"
]
},
"taskGuid": {
"type": "string"
},
"publishDate": {
"type": "string",
"format": "date-time"
}
}
},
"data": {
"type": "object",
"required": [
"code",
"conditions"
],
"properties": {
"code": {
"type": "string"
},
"conditions": {
"type": "array",
"items": [
{
"conditionsType": "object",
"properties": {
"type": {
"enum": [
"A",
"B",
"C"
]
},
"dateBegin": {
"type": "string",
"format": "date-time"
},
"dateEnd": {
"type": "string",
"format": "date-time"
}
},
"required": [
"conditionsType",
"dateBegin",
"dateEnd"
]
}
]
}
}
}
}
}
The conditions array will consist of 1-3 objects described by items. Each object should have a unique conditionsType.
I'm checking validation with this instrument - https://www.jsonschemavalidator.net/
The problem is that this schema does validate the message, But only the first object of array is processed as de. For instance, such a JSON is validated as well (see "conditions" object #2):
{
"header": {
"action": "change_time",
"taskGuid": "someTaskGuid",
"publishDate": "2012-04-23T18:25:43.511Z"
},
"data": {
"code": "f2103839",
"conditions": [
{
"conditionsType": "A",
"dateBegin": "2021-11-22T17:30:43.511Z",
"dateEnd": "2021-11-22T17:35:43.511Z"
},
{
"conditionsType": 123,
"dateBegin": [1,2,3],
"dateEnd": 1
},
{
"conditionsType": "C",
"dateBegin": "2021-11-22T17:30:43.511Z",
"dateEnd": "2021-11-22T17:35:43.511Z"
}
]
}
}
Is that actually the right direction I've chosen for this task ?
Two things. You have a typo in your items schema where you actually want to have type and not conditionsType. Secondly, if the items keyword is an array, the items of the array are validated against the schemas in this order. You want to have the items keyword as a single schema which is then applied to all items. Your corrected schema for copy-paste:
{"$schema":"http://json-schema.org/draft-07/schema","title":"Some schema","description":"Some schema","type":"object","required":["header","data"],"properties":{"header":{"type":"object","required":["action","taskGuid","publishDate"],"properties":{"action":{"enum":["create_work_order","change_time","cancel_work"]},"taskGuid":{"type":"string"},"publishDate":{"type":"string","format":"date-time"}}},"data":{"type":"object","required":["code","conditions"],"properties":{"code":{"type":"string"},"conditions":{"type":"array","items":{"type":"object","properties":{"conditionsType":{"enum":["A","B","C"]},"dateBegin":{"type":"string","format":"date-time"},"dateEnd":{"type":"string","format":"date-time"}},"required":["conditionsType","dateBegin","dateEnd"]}}}}}}

Parse this Json array and extract the value of text

Here is the full json that I want to parse and extract the text that has the value: The product is in second line 3rd row.
Can someone help?
"activities": [
{
"type": "message",
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2019-07-01T15:18:56.8251462Z",
"serviceUrl": "XXXXXXXXXXXXXXXXXXXXXXXXX",
"channelId": "directline",
"from": {
"id": "user1"
},
"conversation": {
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"text": "the milk"
},
{
"type": "message",
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2019-07-01T15:18:57.6856172Z",
"localTimestamp": "2019-07-01T15:18:57.5099359+00:00",
"channelId": "directline",
"from": {
"id": "XXXXXX",
"name": "XXXXXX"
},
"conversation": {
"id": "XXXXXXXXXXXXXXXXXX"
},
"text": "The product is in second line 3rd row",
"attachments": [],
"entities": [],
"replyToId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
],
"watermark": "1"
}
You have specified that this is a full json you have placed in the question, But it is not full json you are missing something.
"activities":
[ //json array start from here
{
"type": "message",
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2019-07-01T15:18:56.8251462Z",
"serviceUrl": "XXXXXXXXXXXXXXXXXXXXXXXXX",
"channelId": "directline",
"from": {
"id": "user1"
},
"conversation": {
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"text": "the milk"
},
{
"type": "message",
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2019-07-01T15:18:57.6856172Z",
"localTimestamp": "2019-07-01T15:18:57.5099359+00:00",
"channelId": "directline",
"from": {
"id": "XXXXXX",
"name": "XXXXXX"
},
"conversation": {
"id": "XXXXXXXXXXXXXXXXXX"
},
"text": "The product is in second line 3rd row",
"attachments": [],
"entities": [],
"replyToId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
], //json array ends here
these are extra lines
***"watermark": "1"
}***
if you want to use this array you need to add a '{' in very top line before
"activities": [
I am placing here a valid json now you can check it on Json parser used to parse json in objects
*Valid Json Here : *
{
"activities": [
{
"type": "message",
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2019-07-01T15:18:56.8251462Z",
"serviceUrl": "XXXXXXXXXXXXXXXXXXXXXXXXX",
"channelId": "directline",
"from": {
"id": "user1"
},
"conversation": {
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"text": "the milk"
},
{
"type": "message",
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"timestamp": "2019-07-01T15:18:57.6856172Z",
"localTimestamp": "2019-07-01T15:18:57.5099359+00:00",
"channelId": "directline",
"from": {
"id": "XXXXXX",
"name": "XXXXXX"
},
"conversation": {
"id": "XXXXXXXXXXXXXXXXXX"
},
"text": "The product is in second line 3rd row",
"attachments": [],
"entities": [],
"replyToId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
],
"watermark": "1"
}

Docusign Send Multiple Envelope to multiple Signer with one to one Document to Signer mapping

I have been working on Salesforce to Docusign Integration. I have multiple documents with Specific signer for each document i.e. one document should be send to one specific user, not all. But I want to do this in one Rest API call to docusign! The documents are stored in Accounts attachments which are created dynamically for each user which are specific to user.
I have been trying this using CompositeTemplates, what I am doing is, adding document and Signer in each inlineTemplate, But it is sending all the documents to all the users in sequence.
I don't want to show all document to all the user, they should see only document specific to them.
Below is the JSON which I am sending:
{
"status": "Sent",
"compositeTemplates": [
{
"inlineTemplates": [
{
"sequence": "1",
"recipients": {
"signers": [
{
"roleName": "Signer 1",
"recipientId": "1",
"name": "Anmol",
"email": "test#gmail.com"
}
]
},
"envelope": {
"status": "Sent",
"emailSubject": "test1"
},
"documents": [
{
"name": "Doc 1",
"fileExtension": "doc",
"documentId": "1",
"documentBase64": "JVBERi0xLjQKJeLjz9MKN58HkeCg8gJEomcWGJdEFtOYYklsXV2dlT6R6Owc+FXFMNSlpckKM6M/ioTGkROkEjkxBDrgthySkvMxGpQJYapHKWwcwXtRU9GCg=="
}
],
"customFields": {
"listCustomFields": [
{
"value": "00128000003tPKB",
"show": "true",
"required": "false",
"name": "Account",
"fieldId": "1",
"configurationType": "salesforce"
}
]
}
}
],
"compositeTemplateId": "1"
},
{
"inlineTemplates": [
{
"sequence": "1",
"recipients": {
"signers": [
{
"roleName": "Signer 2",
"recipientId": "1",
"name": "Anmol",
"email": "test1#gmail.com"
}
]
},
"envelope": {
"status": "Sent",
"emailSubject": "test2"
},
"documents": [
{
"name": "Doc 2",
"fileExtension": "doc",
"documentId": "2",
"documentBase64": "JVBERi0xLjYNJeLjz9MNCjEzIDAgb2JqDTw8L0xpbmVhcmlmDQoxMTYNCiUlRU9GDQo="
}
],
"customFields": {
"listCustomFields": [
{
"value": "00128000003tPKB",
"show": "true",
"required": "false",
"name": "Account",
"fieldId": "1",
"configurationType": "salesforce"
}
]
}
}
],
"compositeTemplateId": "2"
}
]
}
Any doc, code or suggestions about the approach I am following for this will be very helpful.
To do it in a single api call, specify the excludedDocuments property in the EnvelopeCreate request
excludedDocuments: Specifies the documents that are not visible to the recipient. Document Visibility must be enabled for the account and the enforceSignerVisibility property must be set to true for the envelope to use this.
Here is a sample Json for POST /v2/accounts/{accountId}/envelopes
Note: I have combined both your inline templates into a single inlineTemplate.
{
"status": "Sent",
"emailSubject": "Email Subject to all recipients",
"emailBlurb": "Email body to all recipients",
"compositeTemplates": [
{
"inlineTemplates": [
{
"sequence": "1",
"recipients": {
"signers": [
{
"recipientId": "1",
"name": "recipient one",
"email": "recipientone#dsxtr.com",
"excludedDocuments": [ "2" ]
},
{
"recipientId": "2",
"name": "recipient two",
"email": "recipienttwo#dsxtr.com",
"excludedDocuments": [ "1" ]
}
]
},
"documents": [
{
"name": "Doc 1",
"fileExtension": "doc",
"documentId": "1",
"documentBase64": ""
},
{
"name": "Doc 2",
"fileExtension": "doc",
"documentId": "2",
"documentBase64": ""
}
]
}
],
"compositeTemplateId": "1"
}
]
}
I believe you're looking for documentVisibility on the create envelope call.
There are other supporting documentVisibility endpoints here.

Sorting arrays in Mongo

H have json document with array. As I can't add to beginning of array with push or addtoset I need to sort array. Example
{
"Component": [
{
"Id": "PDP-1",
"Links": {"Link": [
{
"Text": "Western Division",
"Url": "/1x7-en70ai/last-minute-holidays-western-division",
"Title": "Last minute holidays Western Division"
},
{
"Text": "Browse Regions ",
"Url": "/1x7-en6uly-10ts/last-minute-holidays-gambia/regions",
"Title": "Last minute holidays Gambia",
"Style": "BrowseForMore"
},
{
"Text": "City of Banjul",
"Url": "/1x6-en6vq7/holidays-city-of-banjul",
"Title": "City of Banjul Holidays"
},
{
"Text": "Western Division",
"Url": "/1x6-en70ai/holidays-western-division",
"Title": "Western Division Holidays"
}
]},
"Title": "Regions",
"Type": "PDP"
},
{
"Id": "PDP-2",
"Links": {"Link": [
{
"Text": "Bijilo",
"Url": "/1x7-enbmy6/last-minute-holidays-bijilo",
"Title": "Last minute holidays Bijilo"
},
{
"Text": "Browse Cities ",
"Url": "/1x7-en6uly-10tt/last-minute-holidays-gambia/cities",
"Title": "Last minute holidays Gambia",
"Style": "BrowseForMore"
},
{
"Text": "Banjul Beach",
"Url": "/1x6-enakgm/holidays-banjul-beach",
"Title": "Banjul Beach Holidays"
},
{
"Text": "Bijilo",
"Url": "/1x6-enbmy6/holidays-bijilo",
"Title": "Bijilo Holidays"
},
{
"Text": "Brufut Heights",
"Url": "/1x6-encok8/holidays-brufut-heights",
"Title": "Brufut Heights Holidays"
},
{
"Text": "Kololi",
"Url": "/1x6-enpnle/holidays-kololi",
"Title": "Kololi Holidays"
},
{
"Text": "Kotu",
"Url": "/1x6-enq067/holidays-kotu",
"Title": "Kotu Holidays"
}
]},
"Title": "Cities",
"Type": "PDP"
}
],
"Id": "118431",
"Template": {
"PageTemplate": {
"Code": "2B2",
"text": "041 - TEMP2 - COP_CONCOU_{LAST MINUTE}"
},
"Category": {
"Code": "1X7",
"Type": "Product",
"text": "Last minute holidays"
},
"GeoObject": {
"Code": "EN6ULY",
"text": "Gambia, The"
},
"GeoObjectType": {
"Code": "1A",
"text": "Political"
},
"GeoObjectSubType": {
"Code": "10TR",
"text": "Country"
}
},
"Type": "Content",
"Url": "/1x7-en6uly/last-minute-holidays-gambia",
"_id": {"$oid": "528492d4c90fa9fcd0436929"}
}
I want to sort this by Style in Links.Link 'BrowseForMore'. Any idea how to do it? I thought I could add dummy array with push which could then sort it the way I want. Any help appreciated
You appear to want to update the array and keep the sort order with your Links.Link.Style value at the front of the list. In which case use the $sort modifier with update.
db.collection.update(
{ _id: id },
{ $push: { "Links.Link: {$each: [doc], $sort { Style: -1 }}} }
)
The $each operator is required even if there is only one document, but can take many.
if you are trying to use $addToSet to maintain unique documents the official MongoDB line is that sets are considered to be unordered and hence the modifiers are not available here.

Resources