Escaping JSON to avoid changing the insert string - javascript

I have the following json string that should be inserted directly into the database in a single column:
const jsString = JSON.stringify({"escaping":"d\"on't"});
const insertion = [{"a":2,"json":jsString}];
const query = pgp.helpers.insert(insertion,["a","json"],"tbl");
however what actually ends up in the database is:
{"escaping":"d"on't"}
removing the escaping \ in d"on't and making the string invalid json. Is there some way to avoid this?
This would be beneficial since it would be nice if my valid json would remain so.

Don't stringify your data into JSON, use it directly
Set column formatting as JSON, using :json modifier
const data = {escaping: "d\"on't"};
const insertion = [{a:2, json:data}];
const query = pgp.helpers.insert(insertion, ["a", "json:json"], "tbl");
But if your data is always an object, then you don't even need to use the :json modifier, it will be automatically formatted as correct JSON.
For more details see the flexibility of the ColumnSet type. You can manipulate your input data in every thinkable way.

This string in js const jsString = JSON.stringify({"escaping":"d\\\"on't"}); will result in this {"escaping":"d\\\"on't"}
While this string in js const jsString = JSON.stringify({"escaping":"don't"}); will result in this {"escaping":"don't"}

Related

Find elements from concatenate strings in JS

How can I search the values in an Object from strings, something like:
const query = "['arg1']['arg2']"
const renderImage = async (index) => {
const data = await fetchImage(index)
const image = document.querySelector('.div')
image.setAttribute("src", data`${query}`)
}
The fetch function is perfect working.
Edit:
The image source is in the data['arg1']['arg2']. If I use image.setAttribute("src", data['arg1']['arg2']) the code runs fine, but I need to do this dynamically and concatenate strings will help me.
Summing up: can I get the same result data['arg1']['arg2'] concatenating object and "query" (['arg1']['arg2'])?
you can store the path as an array of keys and access it like this
const query = ['arg1', 'arg2']
...
image.setAttribute("src", query.reduce((o, k)=>o[k], data))
It seems you are trying to extract the property names you want, from a poorly formatted string. Ideally, you would get query into a better format to begin with, so you don't have to parse the string. For instance, if you could get query as two separate variables:
const query1 = 'arg1';
const query2 = 'arg2';
image.setAttribute("src", data[query1][query2]);
you could also store query in a better data type to do this, like const query = { arg1: 'arg1', arg2: 'arg2' }; then access with dot syntax data[query.arg1][query.arg2].
But if you must keep query as this weirdly formatted string for some reason, you can do something like this, parsing the string into it's parts, putting them into an array, then using the array to access the right data within data.
let query = "['arg1']['arg2']";
query = query.slice( 2 ).slice( 0, -2 ).split( "']['" );
image.setAttribute( "src", data[query[0]][query[1]] );

Single quotes are added to start and end of JSON

Single quotes are added to start and end of this JSON, after returning it to view as here.
I tried removing the first and last character with JavaScript's substring() method to parse it with JSON.parse(), but it couldn't be removed.
What's the correct way to parsing it?
For those who wants the JSON;
"[{\"ParameterType\":\"Parametre Türü1\",\"DisplayType\":\"ComboBox\",\"Parameters\":[{\"Name\":\"Parametre1\",\"Ids\":[\"9786057751744\",\"9786257069335\",\"9786057580399\",\"0\",\"0\",\"0\"]},{\"Name\":\"Parametre2\",\"Ids\":[\"0\",\"0\",\"0\",\"0\",\"9789751969194\",\"0\"]}]},{\"ParameterType\":\"Parametre Türü2\",\"DisplayType\":\"CheckBox\",\"Parameters\":[{\"Name\":\"Param1\",\"Ids\":[\"9786057751744\",\"9786257069335\",\"9786057580399\",\"0\",\"0\",\"0\"]},{\"Name\":\"Param2\",\"Ids\":[\"0\",\"0\",\"0\",\"0\",\"9789751969194\",\"0\"]}]},{\"ParameterType\":\"Parametre Türü3\",\"DisplayType\":\"ComboBox\",\"Parameters\":[{\"Name\":\"1\",\"Ids\":[\"9786057751744\",\"0\",\"0\",\"0\"]},{\"Name\":\"2\",\"Ids\":[\"9786257069335\",\"0\",\"0\",\"9789751969194\"]},{\"Name\":\"3\",\"Ids\":[\"9786057580399\",\"0\",\"0\",\"0\"]}]}]"
JSON encoded data does not need to be an array, object, it could also be a single string:
console.log(JSON.parse("\"test\""))
And that's what you got. It is a single string. That this string by itself also contains JSON encoded data indicates that the data is encoded twice.
If you do JSON.parse(JSON.parse(data)) you will get the object.
But instead of parsing the data twice, you should find the reason why it was encoded twice and fix that.
This snippet shows what happens if you encode the data twice, and it looks like the data you have shown:
let data = [{"ParameterType":"Parametre Türü1"}]
let encodedOnce = JSON.stringify(data)
let encodedTwice = JSON.stringify(encodedOnce)
console.dir(encodedTwice)
let decodedOnce = JSON.parse(encodedTwice)
let decodedTwice = JSON.parse(decodedOnce)
console.dir(decodedTwice)
Maybe try with JSONStringify()

How To Parse A String Of Concatenated JSON In Browser?

I'm using Socket.IO to move data to the browser. The data sent is a stream of JSON objects, and when it arrives at the browser, it becomes one large string of JSON. The problem is, this JSON can't be parsed by JSON.parse() because it's not "real" JSON.
The data structure can be arbitrary so a RegEx might not do the trick. And this current setup is only temporary. Eventually this stream of JSON will be pre-processed server-side so a stream will not need to be sent to the browser, so I'd like to keep the AJAX/Socket.IO setup I have right now instead of switching over to a JSON stream parser like OboeJS.
What can I do to parse this string of concatenated JSON?
For clarity, the JSON will look like this:
{"a":"A"}{"b":"B"}{"c":"C"}
And I'm trying to parse it in such a way that I can access them like:
console.log(Object.a) //A
console.log(Object.b) //B
console.log(Object.c) //C
In your particular case, you could use Array.prototype.reduce to merge all JSON objects into one:
var unstructuredJson = '{"a":"A"}{"b":"B"}{"c":"C"}';
var jsonArray = "[" + unstructuredJson.split("}{").join("},{") + "]";
var objectArray = JSON.parse(jsonArray);
var result = objectArray.reduce(function(result, item) {
Object.keys(item).forEach(function(propertyName) {
result[propertyName] = item[propertyName];
});
return result;
}, {});
document.body.textContent = JSON.stringify(result);
OP said in some comment:
[...] Each JSON might have nested data like {{}{}}{}{}{}
Then, above approach is broken on this case.
My two cents is that you should put some separator character when you stream these JSON objects and life will be easier: you'll be able to split parent objects easily and you'll just need to change split("}{") with the whole separator.
I suggest you that you use some character that will never happen as part of any property value. You can find a control character on this Wikipedia article: Control character
If each substring is valid JSON but the concatenated part isn't, you can turn the string into a valid array literal and use JSON.parse, then you can process each object using Array methods, e.g. forEach:
var s = '{"a":"A"}{"b":"B"}{"c":"C"}';
var obj = JSON.parse('[' + s.replace(/}{/g,'},{') + ']').forEach(function (obj) {
document.write(JSON.stringify(obj) + '<br>');
});
Or if you want it as a single object:
var s = '{"a":"A"}{"b":"B"}{"c":"C"}';
var obj = JSON.parse(s.replace(/}{/g,','));
document.write(JSON.stringify(obj));
You can use JsonParser to parse concatenated json objects:
ObjectMapper mapper = new ObjectMapper();
JsonFactory factory = new JsonFactory(mapper);
JsonParser parser = factory.createParser(YourJsonString);
List<YourObject> YourObjectList = new ArrayList<>();
Iterator<YourObject> iterator = parser.readValuesAs(YourObject.class);
while(iterator.hasNext()) {
YourObject yourObject = iterator.next();
loginSignalsList.add(yourObject);
}
Split the large string {a:'A'}{b:'B'}{c:'C'} and parse them individually

Passing an array from javascript to ruby with sinatra

What I want to accomplish is to pass a 2D array from javascript to something that ruby will recognize. All objects are strings
I have been using gon-sinatra, but it doesn't do exactly what I need.
I can pass store the string I want to pass as gon.text doing
#temp = gon.text
array.push(#temp)
This doesn't work because it shows gon.text as a nil object type, when I want it as a string. gon.text.to_s returns an empty string, so when I try to display it, nothing happens. alert("<%= #temp %>") // displays an empty string
I'm at a bit of a loss here and don't know the best way to approach this. Would it be better to store the array as a json, and then read in the json using ruby instead?
Yes. Convert your array to json(a string) with js:
var data = JSON.stringify(yourArray);
Send the string to your ruby script. Then parse the string into an Array with ruby:
require 'json'
arr = JSON.parse(the_string)
In Javascript you do something like the following:
var myArray = [ ['str1','str2'], ['str3','str4'] ];
$.get('/endpoint', { myArray: myArray })
And your endpoint with sinatra would be:
get 'endpoint' do
myArrayStr = params[:myArray]
error!('invalid array') unless myArrayStr
#myArray = JSON.parse(myArrayStr)
gon.rabl 'goners/yourFile.rabl', :instance => self
end
And in your gon file you would reference this with:
alert(gon.myArray[0][0]); // str1

Generating nodes using ruby and displaying them with javascript error

So Im trying to extract nodes from my database (by going through it recursively) and then displaying the json code i have to a javascript library. The problem is that the library is not identifying the json array output because it has extra quotation marks and a slash (/). Here is the code:
data = {
"nodes":
"\"User1:{'color':'green','shape':'dot','label':'You'},
User2:{'color':'green','shape':'dot','label':'You'},
User3:{'color':'green','shape':'dot','label':'You'}\""
,"edges":{}};
And I want it to look something like this:
var data = {
"nodes":{
"You":{'color':'green','shape':'dot','label':'You'},
Ben:{'color':'black','shape':'dot','label':'Ben'},
David:{'color':'black','shape':'dot','label':'David'}
},
"edges":{
You:{ Ben:{}, David:{} },
Ben:{ David:{}}
}
};
In my user_controller I am using this:
def make_json(node, string = "")
node[1].each do |n|
string += node[0] + "{'color':'green','shape':'dot','label':'You'},"
return make_json(n, string )
end
return string + node[0] + "{'color':'green','shape':'dot','label':'You'}"
end
And finally, this:
#data = {}
#data['nodes'] = make_json(#user_tree[0]).to_json
#data['edges'] = {}
I tried using the replace method, but the data variable doesnt seem to be a String so I can't just replace the quotation marks. I'd appreciate any sort of help.
Thanks!
The reason for the extra \" in the output is that you are calling to_json on the return value from your make_json method which is a string.
Its hard to see exactly what you are trying to do in make_json, but assuming that you want to use the output as a value in your #data hash and then convert that to json I think you would be better off having make_json build a hash and return that. Generally when returning a JSON response the easiest solution is to build a data structure out of Ruby hashes and arrays and then call to_json on that. Here is a much simplified example (I don't know what the #user_tree is so I don't understand the recursive step but I hope this gives you the general idea):
def make_json(node, hash = {})
node[1].each do |n|
hash[n[0]] = {:color => 'green', :shape => 'dot', :label => n[0]}
end
hash
end
If you try to construct the JSON string yourself it is easy to trip up. The output that you say you are aiming for is not valid JSON though it may be valid JavaScript. Strings need to be wrapped in double quotes, e.g.
"Ben": {"color": "black", "shape": "dot", "label": "Ben"}
rather than:
Ben:{'color':'black','shape':'dot','label':'Ben'}

Categories

Resources