Methodology Approach - json string/output - javascript

Hope this question is up to par for SO. I've never posted before but looking for some info in regards to approaching a task I have been assigned.
I have a page with Form information, some simple fields that I've got going.
The page outputs a json string of the form fields and writes them to a text file.
What I need to do is use the key: values to fill in a bash script to output to a hotfolder for ingestion into the production environment.
The "addmore" array needs to determine the number of filename fields produced. I should add that this is dynamic, the "addmore" array may contain 1 entry, or up to technically an unlimited number. This number will fluctuate, though.
JSON Output:
{"formatcode":"JFM","serialnumber":"555","callletters":"555","rotator":"555","addmore":["555","444","333",""]}
How can I use the key : value pairs to output this into a file like below:
{"type":"sequential","items":[
{"filename": "/assets/$formatcode/$serialnumber/$addmore1", "description":"First item"},
{"filename": "/assets/$formatcode/$serialnumber/$addmore2", "description": "Second item"},
{"filename": "/assets/$formatcode/$serialnumber/$addmore3", "description": "Third item"}
]}

This should do the trick, I'm using ES6 string templates to create the dynamic filename and description. The resulting object should have addmore.length items, so we reduce based on data.addmore, creating the basic object as our starting point ({ type: "sequential", items: [] }) and pushing the dynamic strings into output.items on each iteration.
const data = {
"formatcode":"JFM",
"serialnumber":"555",
"callletters":"555",
"rotator":"555",
"addmore":[
"555",
"444",
"333",
]
};
const desiredOutput = data.addmore.reduce((p, c, index) => {
p.items.push({
filename: `/assets/${data.formatcode}/${data.serialnumber}/${c}`,
description: `Item ${index + 1}`
});
return p;
}, {
type: "sequential",
items: []
});
console.log(desiredOutput);
If you don't have ES6 available, you can turn the arrow function into a regular function and use the + concat operator instead of string templates.

Related

Neo4j - is there a way to destruct json objects like in javascript

Working with nodejs and neo4j. I have the node-label: Product. one of it's properties is entries: which is a stringfied json, that contain nested objects of type - entry.
when ever a user enter a product link, the amount of it's entry is incremented.
e.g: Entering the product link from Facebook page, amount of facebookPage entry should be incremented.
(productId and entry are arguments of the server-endpoint that route to that query. )
the current query:
MATCH (p:Product {id: $prodcutId})
WITH apoc.convert.fromJsonMap(p.entries).facebookPage AS jsonEntries, p
SET p.entries = apoc.convert.toJson({facebookPage: { link: jsonEntries.link, amount: jsonEntries.amount + 1}})
RETURN p as product
with one entry (facebookPage), the query is working fine.
but with more than one(e.g: instagramPage), i need a way to save the former entries data.
with javascript i would have done something like this:
SET p.entries = apoc.convert.toJson({...jsonEntries, $entry: { link: jsonEntries.link, amount: jsonEntries.amount + 1, min: 1 }}})
Is there a way to achieve this behavior ?
i saw the APOC dot notation for destructing json object.
link to the docs
using it with my case, it would look something like this
MATCH (p:Product {id: 'b80a61ea4a40408f847214fa3ccf9067'})
WITH apoc.convert.fromJsonMap(l.entries) AS jsonEntries, l
SET l.entries = apoc.convert.toJson(jsonEntries{.instagramPage, facebookPage: { link: jsonEntries.facebookPage.link, amount: jsonEntries.amount + 1 }})
RETURN l as p
but this requires specifying any of the entries, which isn't desired. There will be a lot of entries, and it will make the query hard to maintain. also, the query will need to be updated any time there is a new entry.
product structure:
{
"entries": "{"facebookPage":{"amount":1,"link":"www.facebook.com"},"instagram":{"amount":1,"link":"www.IG.com"}}",
"id": "b80a61ea4a40408f847214fa3ccf9067",
"title": "Guitar"
}
}
entry structure:
{
amount: 0,
link: 'some-link.com',
}
The destructuring you're using there isn't an APOC feature but just vanilla Neo4j. You can destructure all properties using the .* selector - see the last example on the map projection documentation page.
For you then, we'd replace .instagramPage with .*:
MATCH (p:Product {id: 'b80a61ea4a40408f847214fa3ccf9067'})
WITH apoc.convert.fromJsonMap(l.entries) AS jsonEntries, l
SET l.entries = apoc.convert.toJson(jsonEntries{.*, facebookPage: { link: jsonEntries.facebookPage.link, amount: jsonEntries.amount + 1 }})
RETURN l as p
Here's a minimal example showing .* working just to play around with:
WITH {instagramPage: {link: "instagram.com"}} AS entry
RETURN entry {.*, facebookPage: {link: "facebook.com"}}
Output:
{
"facebookPage": {
"link": "facebook.com"
},
"instagramPage": {
"link": "instagram.com"
}
}
Happily, destructuring this way also replaces existing fields in the map with updated values when there's a collision:
WITH {instagramPage: {link: "instagram.com"}} AS entry
RETURN entry {.*, instagramPage: {link: "newinstagram.com"}}
Output:
{
"instagramPage": {
"link": "newinstagram.com"
}
}

Modify an array of objects inside an array of objects in js

Hello developers I'm trying to modify an array of objects inside an array of objects before deploying its result to Redux reducer.
The array is obtained through a request to an endpoint, reason why i must to create an instance of writable copy of it , and then proceed on the process
Lest say i have this array:
allProducts= [
{
"product_type": "Bikes",
"product_imgs": [
{
"id": 5,
"url": "Mountain Bike/Screenshot (200)"
},
{
"id": 6,
"url": "Mountain Bike/Screenshot (200)"
}
],
"product_name": "product test 1"
},
{
"product_type": "Bikes",
"product_imgs": [
{
"id": 7,
"url": "City Bike/banderaa"
},
{
"id": 8,
"url": "City Bike/banderaa"
}
],
"product_name": "product test 2"
}
]
I would like to modify the items inside the array product_imgs of each object , but for that , having in mind this array comes from a request , i do create a readable copy an over that i set the logic.
let instance=[...allProducts];
then using a double for each (though i also tried using a doule for loop) i reach till every image inside the array of objects product_imgs of each object :
instance.forEach(array=>array.product_imgs.map(element => {
this.imgDownLoaderFirebase
.ref(element.url)
.getDownloadURL()
.toPromise()
.then((url) => {
console.log(url);
//then in this space once the url of some firebase endpoint is reached and else
//i would like to modify that object inside the array product_imgs which is at the same time
//part of the instance array.
//For that i expose that this new url gotten would be asigned as the new
//value thus
element = { ...element };
element.url=url
console.log(element);
console.log(instance);//Printing the general array in order to check if changes committed
})
})
I want to specify that i use first a foreach and then a map in order to modify the inner array of objects result , but using a double for each doesn't precisely inmprove this situation:
instance.forEach(array=>array.product_imgs.forEach(element => {........
Then checking the logs , the element (item url) inside the array of objects product_imgs of the array of obejcts instance , is modified , but the external array containing the inner modified not
How could i improve this?
Thanks
If your goal is to extract all product_img values from your array, you could try something like the following :
// This line will convert your array of object into an array of array of urls, using a destructuring process
const urls = allProducts.map(({ product_img }) => product_img);
// This line will merge the previous result into a single-level array of urls that you can iterate onto.
const result = [].concat([], ...res);
Edit : I forgot to mention that this process will in fact return an array of objects including your id and url.

How to access the img value? javascript

I have an array of objects with several properties, one of them is called 'file', of which there are two types as represented below
const products = [
{
functional_id: "2_recharges",
quantity: 1,
title: "Coffret empreinte rouge",
file: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAA…em3dIEUUE1O4fn/M8l6v+f6VPgptdk2plAAAAAElFTkSuQmCC"
},
{
functional_id: "sacs_blancs",
quantity: 1,
title: "Sacs blancs",
file: "data:image/;base64,"
}
]
It's the first time I work with image files and I don't know how to differentiate to create a condition so that only those containing the word 'png' in its value are displayed, in the case of the example the first one, since those that are like the second one don't display any image
I tried to treat them as a string to check if they contained the value string but it doesn't work, as I understand that they are not strings.
If someone can give me an idea of how to create my condition. Thank you very much in advance
You will want to use the js filter method to check whether the file includes 'png'.
const products = [{
functional_id: "2_recharges",
quantity: 1,
title: "Coffret empreinte rouge",
file: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAA…em3dIEUUE1O4fn/M8l6v+f6VPgptdk2plAAAAAElFTkSuQmCC"
},
{
functional_id: "sacs_blancs",
quantity: 1,
title: "Sacs blancs",
file: "data:image/;base64,"
}
]
const pngImages = products.filter(product => product.file.includes('png'))
console.log(pngImages)
this simple filter returns you just only those products that have png in file string
products.filter(product => product.file.match('png').length);

How to modify an element in an embedded list in dynamodb with document client

I have a DynamoDB table where each item in the table has an array of comments as an attribute. My schema looks something like this:
{
"id": "abc",
"name": "This is an item"
"comments": [
"commentId": "abcdefg",
"commentAuthor": "Alice",
"commentDetails": "This item is my favourite!"
]
}
I want to be able to edit an individual comment by its commentId, but it's not clear how to write a DynamoDB expression for this update (I'm using DocumentClient).
How can we update an entry in an embedded array in Dynamo? Is it possible to update by array index, or by a query expression?
I think there should be some modification to your data model.You should have used dynamodb map for this just make your commentId as a key to access each comment
{
"id": "abc",
"name": "This is an item"
"comments": {
"abcdefg":{
"commentAuthor": "Alice",
"commentDetails": "This item is my favourite!"
}
}
}
Then the query would look like this and you must know two things to update the comment 1 is Item id and 2 is comment id
var params = {
TableName: Tablename,
Key: {id: "abc"},
UpdateExpression:"set comments.#abcdefg.commentDetails=:val1",
ExpressionAttributeNames: {
"#abcdefg":"abcdefg"
},
ExpressionAttributeValues:{
":val1":"New comment text"
}
}
db.update(param,callback);
Please Let me know and pardon me,explain your question if i misunderstood as i did not have enough points to clear my doubts in comment.
Personally, I would not put items I want to edit or access frequently this far away from the primary key. Remember DynamoDB is basically a key-value store, so whenever you want to access stuff it's always better to have those items exposed through primary keys.
So what could you do about this, in my opinion, the best way is to slightly alter your data model. So I would create a table with a primary key ID and a sort key of the item type. In your case, you would now have two item types, "Item", and "comment_[commentID]".
Each comment could have the author and details fields as its attributes so something like this:
- [ID - ITEMTYPE] - NAME
- "abc" - "item" - "This is an item"
- [ID - ITEMTYPE] - AUTHOR - DETAILS
- "abc" - "comment_abcdefg" - "Alice" - "This item is my favourite!"
Now if you want to get all comments for an item you simply query for the item ID with the sort key starts with "comment". If you want to edit a comment you could simply get this item by adding the ID to the sort key which would result in an exact match. (also this would be VERY fast).
There are several ways in which you could make this even more flexible but this should be enough to do what you asked for.
So sorry I just read your comment on the other answer, of course, you can add a sorting number in between the comment and the ID field in the item type sortkey this way the comments would sort automatically in that order(or reverse off course).
Is it possible to update by array index...?
Yes, it's quite easy if you know the index. This worked for me in my local localhost:8000/shell/ just now. I assumed that each comment element in the comments list is an object and that you forgot the brackets {} around the comment attributes in your example. Please let me know if I misunderstood or if there's more to your needs.
var params = {
TableName: 'table_name',
Key: { // The primary key of the item (a map of attribute name to AttributeValue)
id: 'abc', //(string | number | boolean | null | Binary)
// more attributes...
},
UpdateExpression: 'SET comments[1] = :value', // String representation of the update to an attribute
// SET set-action , ...
// REMOVE remove-action , ... (for document support)
// ADD add-action , ...
// DELETE delete-action , ... (previous DELETE equivalent)
ExpressionAttributeValues: { // a map of substitutions for all attribute values
':value': {
commentId: 'abcdefg1',
commentAuthor: 'Alice',
commentDetails: 'changed'
}
},
ReturnValues: 'NONE', // optional (NONE | ALL_OLD | UPDATED_OLD | ALL_NEW | UPDATED_NEW)
ReturnConsumedCapacity: 'NONE', // optional (NONE | TOTAL | INDEXES)
ReturnItemCollectionMetrics: 'NONE', // optional (NONE | SIZE)
};
docClient.update(params, function(err, data) {
if (err) ppJson(err); // an error occurred
else ppJson(data); // successful response
});
Output:
This is the way I used to deactivate users from a UsersCategoryTable:
const userIdx = users.map(user => user.M.id.S).indexOf(userId)
const deactivateUserParams = {
TableName: USERS_CATEGORY_TABLE_DEV,
Key: {id: {S: catId}},
UpdateExpression: `SET updatedAt = :updated_at, #users[${userIdx}].#status = :new_status`,
ExpressionAttributeNames: {
"#users": 'users',
"#status": "status"
},
ExpressionAttributeValues: {
":new_status": {"S": "INACTIVE"},
":updated_at": {"S": new Date().toISOString()}
},
ReturnValues: "UPDATED_NEW",
}

Regex for parsing single key: values out of JSON in Javascript

I'm trying to see if it's possible to lookup individual keys out of a JSON string in Javascript and return it's Value with Regex. Sort of like building a JSON search tool.
Imagine the following JSON
"{
"Name": "Humpty",
"Age": "18",
"Siblings" : ["Dracula", "Snow White", "Merlin"],
"Posts": [
{
"Title": "How I fell",
"Comments": [
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]
}
]
}"
I want to be able to search through the JSON string and only pull out individual properties.
lets assume it's a function already, it would look something like.
function getPropFromJSON(prop, JSONString){
// Obviously this regex will only match Keys that have
// String Values.
var exp = new RegExp("\""+prop+"\"\:[^\,\}]*");
return JSONString.match(exp)[0].replace("\""+prop+"\":","");
}
It would return the substring of the Value for the Key.
e.g.
getPropFromJSON("Comments")
> "[
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]"
If your wondering why I want to do this instead of using JSON.parse(), I'm building a JSON document store around localStorage. localStorage only supports key/value pairs, so I'm storing a JSON string of the entire Document in a unique Key. I want to be able to run a query on the documents, ideally without the overhead of JSON.parsing() the entire Collection of Documents then recursing over the Keys/nested Keys to find a match.
I'm not the best at regex so I don't know how to do this, or if it's even possible with regex alone. This is only an experiment to find out if it's possible. Any other ideas as a solution would be appreciated.
I would strongly discourage you from doing this. JSON is not a regular language as clearly stated here: https://cstheory.stackexchange.com/questions/3987/is-json-a-regular-language
To quote from the above post:
For example, consider an array of arrays of arrays:
[ [ [ 1, 2], [2, 3] ] , [ [ 3, 4], [ 4, 5] ] ]
Clearly you couldn't parse that with true regular expressions.
I'd recommend converting your JSON to an object (JSON.parse) & implementing a find function to traverse the structure.
Other than that, you can take a look at guts of Douglas Crockford's json2.js parse method. Perhaps an altered version would allow you to search through the JSON string & just return the particular object you were looking for without converting the entire structure to an object. This is only useful if you never retrieve any other data from your JSON. If you do, you might as well have converted the whole thing to begin with.
EDIT
Just to further show how Regex breaks down, here's a regex that attempts to parse JSON
If you plug it into http://regexpal.com/ with "Dot Matches All" checked. You'll find that it can match some elements nicely like:
Regex
"Comments"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")
JSON Matched
"Comments": [
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]
Regex
"Name"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")
JSON Matched
"Name": "Humpty"
However as soon as you start querying for the higher structures like "Posts", which has nested arrays, you'll find that you cannot correctly return the structure since the regex does not have context of which "]" is the designated end of the structure.
Regex
"Posts"[ :]+((?=\[)\[[^]]*\]|(?=\{)\{[^\}]*\}|\"[^"]*\")
JSON Matched
"Posts": [
{
"Title": "How I fell",
"Comments": [
{
"User":"Fairy God Mother",
"Comment": "Ha, can't say I didn't see it coming"
}
]
\{|\}|\[|\]|,|:|(\\-)?\\d+(\\.\\d+)?|".+?"
You can use the following regex and iterate with a match over all tokens of a json. You can tokenize the JSON, but the parsing part has to be implemented by you.
Since you're using JavaScript as I assume from the tags, your best way to encode the JSON stays JSON.parse().
I'm almost 10 years late to the party, but I came up with this.
Not tested in crazier JSONs than this, but it solves my use cases.
const obj1 = {
id: 1,
'name.1': '123',
address: {
'address.1': 'Chicken Dinner Road, 69',
'address.2': 'Psycho lane, 666',
},
'age.1': {
'thisIsSomeCrazyJson.3': 10,
age: 50,
},
types: [
{
id: 22,
'name.name': '123',
typeOption: {
id: 1,
'whoTFWroteThisJSON.2': '123',
},
},
{
id: 32,
'name.1': '123',
},
],
};
const obj2 = {
Name: 'Humpty',
Age: '18',
Siblings: ['Dracula', 'Snow White', 'Merlin'],
Posts: [
{
Title: 'How I fell',
Comments: [
{
'User': 'Fairy God Mother',
'Comment': "Ha, can't say I didn't see it coming",
},
],
},
],
};
function matchKeyDeep(input, pattern) {
return Object.entries(input).reduce((nextInput, [key, value]) => {
const isMatch = pattern.test(key);
if (Array.isArray(value)) {
const arrValue = value;
let nextValue = arrValue.map((arrItem) => {
if (typeof arrItem === 'object') {
return matchKeyDeep(arrItem, pattern);
}
return arrItem;
});
if (!isMatch && Array.isArray(nextValue)) {
nextValue = nextValue.filter((v) => (typeof v === 'object' && v !== null));
if (nextValue.length === 0) return nextInput;
}
nextInput[key] = nextValue;
return nextInput;
}
if (typeof value === 'object') {
const recurse = matchKeyDeep(value, pattern);
if (!isMatch && Object.keys(recurse).length === 0) {
return nextInput;
}
nextInput[key] = recurse;
return nextInput;
}
if (isMatch) {
nextInput[key] = value;
}
return nextInput;
}, {});
}
const res = matchKeyDeep(obj1, /\.\d/);
const res2 = matchKeyDeep(obj2, /Comment/);
console.log(res);
console.log(res2);
First, stringify the JSON object. Then, you need to store the starts and lengths of the matched substrings. For example:
"matched".search("ch") // yields 3
For a JSON string, this works exactly the same (unless you are searching explicitly for commas and curly brackets in which case I'd recommend some prior transform of your JSON object before performing regex (i.e. think :, {, }).
Next, you need to reconstruct the JSON object. The algorithm I authored does this by detecting JSON syntax by recursively going backwards from the match index. For instance, the pseudo code might look as follows:
find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain
With this information, it is possible to use regex to filter a JSON object to return the key, the value, and the parent object chain.
You can see the library and code I authored at http://json.spiritway.co/

Categories

Resources