Accessing JavaScript Sub-properties by Name - javascript

I wrote the following JavaScript function (part of a larger "class") to help ensure anybody using the object stores attribute values in the "values" property.
function _updateAttributes(attribute, value) {
_attributes[attribute] = { values: { value: value }};
}
It works fine for a flat structure, but falls apart when I start trying to use it for sub-properties.
After running the following code:
myEntity.updateAttribute('name', 'Frankenstein');
myEntity.updateAttribute('name.source', 'John Doe');
I'd like the following structure:
{
"attributes": {
"name": {
"values": {
"value": "Frankenstein"
},
"source": {
"values": {
"value": "JohnDoe"
}
}
}
}
}
Instead, it's coming out like this:
{
"attributes": {
"name": {
"values": {
"value": "Frankenstein"
}
},
"name.source": {
"values": {
"value": "JohnDoe"
}
}
}
}
Is there any clean way to write this JavaScript or will I be faced with splitting out the strings and manually building the structure?
NOTE: I realize even the preferred structure is a little odd, but there's a Java object I'm mapping to that expects this format, so I don't have any options here.

You'll have to parse the string (parse is a bit strong, just a single split('.') with a loop).
But frankly, the cleaner way would simply be:
myEntity.name = {values: 'Frankenstein'};
myEntity.name.source = {values: 'John Doe'};

Related

Constructing JSON Schema with anyOf recursive items in array [duplicate]

I was looking around the docs and couldn't find any direct or indirect solution.
Is there any way to get validation on JSON objects without knowing exactly where the specific object is located?
For example, I want to validate the following sub-object:
{
"grandParent": {
"parent": {
"child": {
"name": "John"
}
}
}
}
The object can be part of a larger JSON file the can be structured as follows:
{
"root": {
"someKey": {
"grandParent": ...
},
"grandParent": ...,
...<go in even deeper>: {
"grandParent": ...
}
}
}
Can I create a json schema that validates the object no matter where it is?
Similar example in glob would be: root.**.grandParent.parent.child
You'll need to use a combination of additionalProperties, items, and recursive references.
First, we define the structure you want to validate. You have to define properties for each layer of the object.
Next, you want your root level to reference that definition. Because you're using pre draft 2019-09, you'll need to wrap that reference in an allOf.
Then you want to make sure that for objects, the values have the root schema applied, and for arrays, each item has the root schema applied.
The use of "$ref": "#" resolves to the root of the schema, which creates the cyclical reference.
Some implementations may not like this, but most should be able to handle it.
Here's a live demo of the below schema: https://jsonschema.dev/s/lBrZk
{
"$schema": "http://json-schema.org/draft-07/schema",
"definitions": {
"grandParentToChild": {
"properties": {
"grandParent": {
"properties": {
"parent": {
"properties": {
"child": {
"properties": {
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"allOf": [
{
"$ref": "#/definitions/grandParentToChild"
}
],
"additionalProperties": {
"$ref": "#"
},
"items": {
"$ref": "#"
}
}

Make CreateQueryBuilder return nested object instead of one flat object

I'm using Typescript with TypeORM. Using CreateQueryBuilder, I want to receive a nested object. Instead I'm receiving a single flat object as represented in block number two. How can I fix this?
const x = await getConnection()
.createQueryBuilder()
.select(['reportHead', 'order', 'workOrder'])
.from('report_head', 'reportHead')
.innerJoin('reportHead.workOrder', 'workOrder')
.innerJoin('workOrder.order', 'order')
.where(`order.customer.id = :customerId`, { customerId: req.user.customer.id })
.execute();
How can I avoid the data looking like this:
{
"reportHead_id": "asd",
"reportHead_number": "123",
"workOrder_id": "dsa",
"workOrder_status: "OK",
"order_id": "sda",
"order_whatev": "ks"
}
but rather have a neste object like this:
{
"reportHead": {
"id": ...
},
"workOrder": {
"id": ...
},
"order": {
"id": ...
}
}
The solution was to not use .execute(), but rather .getMany().

Construct a JSON Payload in javascript

I have to construct a JSON payload that looks like this, can someone help me? I am able to get the straight forward one but unable to build a nested payload. How do I go about adding more nested keys, one inside the other. Also some of the keys and values are dynamic and have to replaced with variables.
{
"format_version": "0.2.19",
"alliances": {
"xyz": {
"environments": {
"prd": {
"teams": {
"abc": {
"action": "edit",
"team": "abc",
"projects": {
"prjabc": {
"project": "prjabc",
"cost_center": "0",
"custom_iam_policies": [],
"iam": {
"view_group_email_name": "abc#email.com",
"sre_admin_group_email_name": "xyz#email.com"
},
"allowed_apis": [
"api1",
"api2"
],
"networks": {
"network1": {
"flags": [
"VM"
],
"region": "sample-region",
"preferred-suffix": "routable"
}
}
}
}
}
}
}
}
}
}
}
Let say you have an object as such
items = {
foo: "bar",
something: "useful"
}
and if you wanted to add other properties or add nested object you can do so like this
subitems = { name: "Johnson" };
items['subitem'] = subitems;
After you've added and finalized the object, you can just use JSON.stringify(items) to convert your object into "payload"

Angular - Convert Jackson output to JSON

The server I'm working with changed the REST format from plain JSON:
{
"removedVertices": [
{
"id": "1",
"info": {
"host": "myhost",
"port": "1111"
},
"name": "Roy",
"type": "Worker"
}
],
"id": "2",
"time": 1481183401573
}
To Jackson format:
{
"removedVertices": [
"java.util.ArrayList",
[
{
"id": "1",
"info": [
"java.util.HashMap",
{
"host": "myhost",
"port": "1111"
}
]
"name": "Roy",
"type": "Worker",
}
]
"id": "2",
"time": 1482392323858
}
How can I parse it the way it was before in Angular/Javascript?
Assuming only arrays are affected, I would use underscore.js and write a recursive function to remove the Jackson type.
function jackson2json(input) {
return _.mapObject(input, function(val, key) {
if (_.isArray(val) && val.length > 1) {
// discard the Jackson type and keep the 2nd element of the array
return val[1];
}
else if (_.isObject(val)) {
// apply the transformation recursively
return jackson2json(val);
}
else {
// keep the value unchanged (i.e. primitive types)
return val;
}
});
}
If the api should be restful, then the server should not return none plain json results. I think the server site need to fix that.
I think it is because the server enabled the Polymorphic Type Handling feature.
Read Jackson Default Typing for object containing a field of Map and JacksonPolymorphicDeserialization.
Disable the feature and you will get result identical to plain json.
The main difference i see is that in arrays you have an additional string element at index 0.
If you always get the same structure you can do like this:
function jacksonToJson(jackson) {
jackson.removedVertices.splice(0, 1);
jackson.removedVertices.forEach((rmVert) => {
rmVert.info.splice(0, 1);
});
return jackson;
}

Is it possible to access a json array element without using index number?

I have the following JSON:
{
"responseObject": {
"name": "ObjectName",
"fields": [
{
"fieldName": "refId",
"value": "2170gga35511"
},
{
"fieldName": "telNum",
"value": "4541885881"
}]}
}
I want to access "value" of the the array element with "fieldName": "telNum" without using index numbers, because I don't know everytime exactly at which place this telNum element will appear.
What I dream of is something like this:
jsonVarName.responseObject.fields['fieldname'='telNum'].value
Is this even possible in JavaScript?
You can do it like this
var k={
"responseObject": {
"name": "ObjectName",
"fields": [
{
"fieldName": "refId",
"value": "2170gga35511"
},
{
"fieldName": "telNum",
"value": "4541885881"
}]
}};
value1=k.responseObject.fields.find(
function(i)
{return (i.fieldName=="telNum")}).value;
console.log(value1);
There is JSONPath that lets you write queries just like XPATH does for XML.
$.store.book[*].author the authors of all books in the store
$..author all authors
$.store.* all things in store, which are some books and a red bicycle.
$.store..price the price of everything in the store.
$..book[2] the third book
$..book[(#.length-1)]
$..book[-1:] the last book in order.
$..book[0,1]
$..book[:2] the first two books
$..book[?(#.isbn)] filter all books with isbn number
$..book[?(#.price<10)] filter all books cheapier than 10
$..* All members of JSON structure.
You will have to loop through and find it.
var json = {
"responseObject": {
"name": "ObjectName",
"fields": [
{
"fieldName": "refId",
"value": "2170gga35511"
},
{
"fieldName": "telNum",
"value": "4541885881"
}]
};
function getValueForFieldName(fieldName){
for(var i=0;i<json.fields.length;i++){
if(json.fields[i].fieldName == fieldName){
return json.fields[i].value;
}
}
return false;
}
console.log(getValueForFieldName("telNum"));
It might be a better option to modify the array into object with fieldName as keys once to avoid using .find over and over again.
fields = Object.assign({}, ...fields.map(field => {
const newField = {};
newField[field.fieldName] = field.value;
return newField;
}
It's not possible.. Native JavaScript has nothing similar to XPATH like in xml to iterate through JSON. You have to loop or use Array.prototype.find() as stated in comments.
It's experimental and supported only Chrome 45+, Safari 7.1+, FF 25+. No IE.
Example can be found here
Clean and easy way to just loop through array.
var json = {
"responseObject": {
"name": "ObjectName",
"fields": [
{
"fieldName": "refId",
"value": "2170gga35511"
},
{
"fieldName": "telNum",
"value": "4541885881"
}]
}
$(json.responseObject.fields).each(function (i, field) {
if (field.fieldName === "telNum") {
return field.value // break each
}
})

Categories

Resources