How to parse json file to dictionary - javascript

i want parse a json file to Dictionary and want write some data to it.
this is what i have, but i become a empty Dictionary
var users = {};
fs.readFile('login.json', function read(err, data) {
if (err) {
throw err;
}
users = JSON.parse(data);
});

In Node.js you can require JSON files, so your code could simply become:
var users = require('./login.json');
Though note the data will be cached, so if your login.json file changes without an application restart the users object will stay the same.

readFile is an asynchronous function. If you want to do anything with the data in it, you must do so in the callback function (or at some point after you know the callback has been run).
You may want to use readFileSync instead.

Related

Better way of passing Mongodb query data to Pug

I am looking for a better way of passing data to my index.js file in a webdev application. Note I really only have about a month of webdev experience so this is likely due to lack of experience. here is my software flow:
I query data in a route handler before the page is rendered. I then pass this data to the rendered page (note i need to keep some of the key-vals hidden. However aggregation works).
exports.getPlotView = async(req, res, next) =>{
//grab the module to query from, stored as var.testModel
const qParse = new PlotQueryParse(req.query).parseObj();
// console.log(qParse)
// const testblockName = qParse.testblock+"Name" ;
// const limitName = qParse.limitname;
const aggregationObj = {$match:
{'jobId':qParse.jobId, '<key2>':<val2>, "<key>":"<val>"}
}
const data = await qParse.testModel.aggregate([aggregationObj]);
console.log(data[0])
const dataString = JSON.stringify(data[0]);
//parse the url to make the query
res.status(200).render('testPlotView', {
pageHeader: "Test",
subHead: "Test summary",
IPn: "IPn",
inData:dataString
});
}
data is passed to pug template. The template uses this as a hidden element
extends base
block content
div.hide_data #{inData}
div#dataviz
now in my index.js script (listens for evenets), the data is loaded from the page and then stored for post processing. I would like to directly access the variable instead of having it hidden then accessing the DOM element.
window.addEventListener('load', function(){
if(window.location.href.includes('testplotdata')){
console.log('its a me mario')
//if we are in a test plot data page, lets plot
var jsonObject = JSON.parse(document.querySelector('.hide_data').innerHTML);
console.log(jsonObject['testData'])
//post processing code ....
}
})
Again, I want a way to grab my queried data without saving it as a DOM element then accessing it in my external event listener script.
Thanks!
Instead of storing data in HTML, add inline script to your template to store it in a global variable instead. So replace div.hide_data #{inData} with:
script.
var inData = !{inData}; // inData passed by backend must be a string
// representing a valid JS object (JSON will do)
Now you just access inData as a ready native object in your external script (which you need to make sure load after the above script, putting it at the end of <body> will do)
// No need: var jsonObject = JSON.parse(document.querySelector('.hide_data').innerHTML);
console.log(inData); // Go ahead with the data

How to run javascript based rules against a page?

I would like to run some rules against pages. These rules are essentially functions that check the page for information. They can be simple as in 'check if the page has a title tag' or more complex like 'check if all links on the pages are whitelisted based on example.com/allowed_links.json'.
The rules would be run on the page on-demand only and come from a trusted source.
My first approach has been to create a rule service that sends back an javascript array of rules. All the client then has to do is go over the array and run each function in it. The response is a standard object {rule: [name], pass: [true|false], message: [some message about success/failure]}
Since this is on demand only, we fetch the rules from the service and run 'eval' on it.
EDIT: The response from 'mysite/rules' looks like this
RULESYSTEM.rules.push(function1() {...});
RULESYSTEM.rules.push(function2() {...});
...
const RULESYSTEM = {
rules: [],
};
let rules = fetch('mysite/rules')
let rulesscript = await rules.text();
eval(rulescript)
...
//eval will populate the previously declared rules array.
let pass = true;
for(let i=0; i < RULESYSTEM.rules.length; i++) {
let rule = RULESYSTEM.rules[i];
//This obj has only one property. Get that one.
let result = rule();
pass = pass && result.pass;
}
...
This works perfectly fine. However it is receiving a lot of pushback as 'eval' is considered evil and to be avoided at any cost. The security is not an issue here since the source is within the organization itself and thus trusted.
Are there any other ways to implement a system like this.
It would appear that all you're attempting to do is to retrieve JSON data and transforming it into a javascript object.
fetch('mysite/rules')
.then(res=>res.json())
.then(data=>{
//TODO: handle data which is your object/array
console.log(data)
})
Thus no need for eval. Also you need to remember that fetch returns a promise and that rules.text() and rules.json() also returns a promise. The way you've currently written it won't work anyway.
According to MDN
The json() method of the Body mixin takes a Response stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as JSON.
To answer your question:
Is it possible to return javascript code as JSON
That's clearly a no, however there are alternatives ! You can simply fetch javacsript as text (as you've done) and programmatically create a script tag, load your javascript text in it and append it to your HTML file.
Or even better, you can simply dynamically create a script tag with the URL of your server endpoint sending javascript and append it to your HTML file.
Something like:
const script = document.createElement("script");
script.onload = function(){
console.log("script loaded");
}
script.src = '/some/url/here';
document.body.appendChild(script);
I am going to add this as an answer. I will use some dummy data you can query based on an endpoint
Route("get-functions")
Response getJSFunctions(List<string> js_to_load){
var options = getData(); //returns a list
var guid = new Guid()
var fp = File.open(guid.toString() + ".js", "w+")
var out = "var fns = [" + options.join("\n") + "];";
fp.write(out);
fp.write(" var runner = options => fns.forEach(fn => fn(options) );");
fp.close()
return new Response({url: guid.toString() + ".js"})
}
Js:
$.json("get-functions", data => {
let script = document.createElement("script");
script.src = data.url;
document.head.appendChild(script)
runner(options);
});
So what is happening is that you build a Temp JS FIle containing all JS Functions you want run, then add that file dynamically to the runtime. Then you have a function which will always be available called runner, which you can immediately call.
Runner will iteratively call each function with a global list of options across the functions, which you can define on the clientside.
Instead of using C#, you can use any serverside or even Javascript if you are using node as your backend. You need DB Access and file creation access on the host machine. You will also want to delete the GUID files ocassionally as they are just one and done use files, so you can delete them all every 5 minutes or something.
I dont have the means right now to create a running sample. I can create something a little later with Python if you like as the backend.

Piping console.log() contents to a .txt file in Node.js

I have a Node.js file that outputs a bunch of test results, easily >1000 lines, to Terminal. The file looks something like this:
launchChromeAndRunLighthouse('https://www.apple.com/', flags).then(results => { console.log(results); });
The console.log() is only there because I couldn't figure out another way to view the results. I need a way to create a file through Node.js, not the command line, that contains all of the CLI output/results.
I thought that fs.appendFile('example.txt', 'append this text to the file', (err) => {}); could be of use, but what I need to "append" to the file is the function's results. When I try that, the file only contains [object Object] instead of the actual results of the tests.
I'm a beginner to Node, any advice is highly appreciated.
You are close, but you need to include the appendFile inside of your other function. This assumes that your 'results' object is of the string type. If not then you need to get the string version of this object.
The lighthouse docs specify the format of the log information that is returned. If you add output: json to the flags object then you can use it lik
launchChromeAndRunLighthouse('https://www.apple.com/', flags).then(results => {
fs.appendFile('example.txt', JSON.stringify(results), (err) => {
console.log('error appending to file example.txt');
});
});

How do I rewrite the JSON object in a file using file system in Node Js

I have came across the read and write operations using fs in Node Js.
My scenario is like, I have a file having the data like ,
[
{
"Pref":"Freedom",
"ID":"5545"
},
{
"Pref":"Growth",
"ID":"8946545"
}
]
I have to replace the Pref of the element whose ID is 5545 using Node js.
How can I do it. Thanks
To do what you want, you wound need to:
read JSON data from the file with fs.readFile()
parse the JSON with JSON.parse()
find the correct object in the array
change the object
serialize the object back to JSON with JSON.stringify()
write the file with fs.writeFile()
but this is not that simple as it may look like, because you will have to:
add locking to writes so that you never do two writes at the same time
add locking to reads so that you never read while the write is in progress
handle incorrect JSON
handle cases of objects that cannot be serialized
avoid blocking operations (those with "Sync" in their name) anywhere else then in the first tick of the event loop
Considering all of that you should consider using a database to store any data that changes. Some databases like Mongo, Postgres or Redis need to be run as standalone application either on the same or on a different server. Some embedded databases like SQLite don't need a standalone process and can be run directly in your application.
It's not that it is impossible to write to JSON files and then read those files as needed, but the amount of work that you'd have to do to synchronize the access to the data all without accidentally blocking the event loop in the process is much more difficult than just using any database as intended.
You have some data:
const data = [
{
"Pref":"Freedom",
"ID":"5545"
},
{
"Pref":"Growth",
"ID":"8946545"
}
]
First we need to find the element you want to change (use [0] to only select the first in case there are multiple items with ID 5545:
const objectToChange = data.filter(item => item.ID === "5545")[0]
And then change it!
objectToChange['Pref'] = "Liberty"
We can see the change reflected in the data object:
console.log(data)
// [{
// ID: "5545",
// Pref: "Liberty"
// },{
// ID: "8946545",
// Pref: "Growth"
// }]
1- Load file: let json = JSON.parse(fs.readFileSync('file.json', 'utf-8'));
2- Update content:
json = json.map(el => {
if(el.ID === "5545") {
el.Pref = "TEST";
}
return el;
});
3- Save again maybe?
fs.writeFileSync('test.json', JSON.stringify(json), 'utf-8');

JSON Error when parsing "... has no method 'replace'"

Let me preface this with the admission that I am a complete programming and javascript noob and that fact is the source of my trouble.
I'm trying to populate a large array of custom objects from a text file that I've saved to with json.stringify. When I grab the file contents and json.parse(them), I get the following error:
var backSlashRemoved = text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '#'
^
TypeError: Object (contents of file) has no method 'replace'
The code that causes this error is:
fs.readFile('/savedcustomobjectarray', function (err, data) {
var customobjectarray = json.parse(data);
});
I'm guessing I'm going about this all wrong. I saw some people mention serializers for this sort of thing, but I wanted to double check if that's what I needed (and maybe get some direction in how to use them in this context). It seems like the stringify output is fine, though, so I'm not sure why JSON can't just put humpty dumpty back together again. Any help would be greatly appreciated.
EDIT:
The text.replace line is in /vendor/commonjs-utils/lib/json-ext.js, not my code. I assumed this was part of JSON. Perhaps I am wrong? Is there a different way to parse my object array through JSON?
fs.readFile takes 2 or 3 arguments, when passing only the filename and a callback, then your callback function will get the following two arguments (err, data) where data is a raw buffer.
So the right way to do it would be:
fs.readFile('/savedcustomobjectarray', function (err, data) {
var customobjectarray = JSON.parse(data.toString('utf8'));
});
data.toString takes the encoding as the first argument.
Alternitavley you could specify the encoding as the second argument to the fs.readFile and have it pass a string to the callback:
fs.readFile('/savedcustomobjectarray', 'utf8', function (err, data) {
var customobjectarray = JSON.parse(data);
});
Node API docs is your best friend!

Categories