I have a weird looking object that I would like to turn into an object with multiple objects. (what I mean by multiple objects in nested objects) The current object looks like this:
{
'test.txt': "This is a test\r\n\r\nI hope it'll work",
'testy.js': 'console.log("thonk");\r\n',
'thonk\\i swear\\egg.txt': 'am going to be happy?',
'thonk\\pls work.txt': 'dasdas'
}
And I want it to look like this:
{
"test.txt": "This is a test\r\n\r\nI hope it'll work",
"testy.js": "console.log('thonk');\r\n",
"thonk": {
"I swear": {
"egg.txt": "am going to be happy?"
},
"pls work.txt": "dasdas"
}
}
Edit:
here's what my code is (if u need it):
var fs = require("fs");
var path = require("path");
var walk = function (dir, done) {
var results = [];
fs.readdir(dir, function (err, list) {
if (err) return done(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
file = path.resolve(dir, file);
fs.stat(file, function (err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function (err, res) {
results = results.concat(res);
next();
});
} else {
results.push(file);
next();
}
});
})();
});
};
var root = "test";
var data = {};
walk("test", function (err, results) {
if (err) throw err;
for (i in results) {
data[
results[i].replace(__dirname + "\\" + root + "\\", "")
] = fs.readFileSync(results[i], "utf8");
}
console.log(data);
});
This can be done by combining Object.keys() and Array.reduce() as follows:
const source = {
'test.txt': "This is a test\r\n\r\nI hope it'll work",
'testy.js': 'console.log("thonk");\r\n',
'thonk\\i swear\\egg.txt': 'am going to be happy?',
'thonk\\pls work.txt': 'dasdas'
}
const result = Object.keys(source).reduce((target, k) => {
const keys = k.split('\\');
if (keys.length == 1) {
target[k] = source[k];
} else {
const nestedObj = target[keys[0]] || {};
keys.slice(1).reduce((o, nestedKey, i) => {
const value = i < keys.length -2 ? {} : source[k];
o[nestedKey] = value;
return value;
}, nestedObj);
target[keys[0]] = nestedObj;
}
return target;
}, {});
console.log(result);
So you should create new object, then go through each element, combining items that you need and placing them to a new one.
Related
I am creating a pie chart which shows how much disk space is available/used on my linux box. However, I am unsure how to parse the data onto a microservice url. Help will greatly be appreciated.
Here is what I have at the moment:
Router:
router.route('/linux_disk').get(disk.get_linux_disk)
Controller:
function get_linux_disk(req, res, next) {
try {
var cmd = `df ~`;
exec(cmd)
rows = [];
rows.push({"Command": cmd});
if (rows.length >= 1) {
res.status(200).json(rows);
} else {
res.status(404).end();
}
} catch (err) {
next(err);
}
}
You might try the approach below, we create a row object for each entry that the df
command creates. Once you have this you should be able to create your pie chart from this:
const { exec } = require('child_process');
const { promisify } = require('util');
const execPromise = promisify(exec);
async function get_linux_disk(req, res, next) {
try {
const result = await execPromise(`df ~`)
const lines = result.stdout.split("\n");
const keys = lines[0].split(/\s+/ig);
// Skip the header row when assigning objects..
const rows = lines.slice(1).map(line => {
// Parse each line..
const values = line.split(/\s+/ig);
return keys.reduce((o, k, index) => {
o[k] = values[index];
return o;
}, {})
});
res.status(200).json(rows);
} catch (err) {
res.status(500).send(err.message);
}
}
The resulting JSON will look a bit like so :
[
{
"Filesystem": "/dev/sda1",
"1K-blocks": "10253588",
"Used": "7971516",
"Available": "1741504",
"Use%": "83%",
"Mounted": "/"
}
]
I'm trying to understand why the debugger does not go into the callback function, it does not give any errors or any results... It just jump over connect.query!
When I run in the mySQL workbench the code runs and I get the data, so the query is not incorrect either.. (You can see the example from the creator of the mysql node package, I can't understand why I can't get into the callback)
SELECT * FROM eclasstree WHERE numberofdigits = '8';
Here is the part of the code that does not enter the callback, all the other SQL queries works above works just fine...
connection.query("SELECT * FROM eclasstree WHERE numberofdigits = '8'", function(error, results, fields) {
if (error) {
throw error;
}
console.log(results, fields);
});
index.js // route /generatewordsconnectedtoeclass
require("console-stamp")(console, "[HH:MM:ss.l]");
const express = require("express");
const router = express.Router();
const { Database, mySQLConnectionDetails, connection } = require("../helpers/mySQL");
const { cleanseString, cleanseStringToArray, generateCountDuplication, sortValuesBykey, generateScoreArray, calculateAverage, replaceAbbreviationWithExpansion } = require("../helpers/stringFixers");
const database = new Database(mySQLConnectionDetails);
router.get("/generatewordsconnectedtoeclass", (req, res) => {
const eClassArray = [];
let eClassCode = "";
connection.query("SELECT * FROM eclasstree WHERE numberofdigits = '8'", function(error, results, fields) {
results.forEach(eclassobj => {
eClassCode = eclassobj.code;
connection.query(`SELECT itemnumber, cleanname, eclass FROM partnumbersclassified WHERE eclass = '${eclassobj.code}'`, function(error, results, fields) {
let stringToArray = [];
let countObject = [];
if(results.length > 0) {
stringToArray = cleanseStringToArray(results, "cleanname");
}
if(stringToArray.length > 0) {
countObject = generateCountDuplication(stringToArray);
// console.log(countObject);
for (const property in countObject) {
if (countObject.hasOwnProperty(property)) {
// console.log(property + " : " + countObject[property] + " : " + eClassCode);
// console.log(property);
// const obj = {
// eclasscode: `${eClassCode}`,
// wordcount: `${countObject[property]}`
// };
// obj[property] = `${countObject[property]}`;
// const obj2 = obj;
// connection.query(`INSERT INTO wordsconnectedtoeclasscode (eclasscode, word, wordcount) VALUES (${eClassCode}, ${property}, ${countObject[property]})`, function(error, results, fields) {
// const post = {word: "Hello", wordcount: "1"};
// connection.connect();
connection.query("SELECT * FROM eclasstree WHERE numberofdigits = '8'", function(error, results, fields) {
if (error) {
throw error;
}
console.log(results, fields);
});
// connection.query("INSERT INTO posts SET ?", post, function(error, results, fields) {
// //connection.query("INSERT INTO wordsconnectedtoeclasscode (eclasscode, word, wordcount) VALUES ('12345123', 'balle', '2'})", function(error, results, fields) {
// if (error) throw error;
// console.log(fields);
// console.log(results);
// connection.end();
// });
}
}
}
});
});
});
res.json({});
});
module.exports = router;
If I do "step in-to" I can see the "sql" is defined with the query, but the "cb" is undefined!
With help of #Patrick Evans I solved it.
I read up on the docs for the mysql node package and they do not follow the standard mysql queries. So after I changed it, it worked!
const obj = {
eclasscode: `${eclassobj.code}`,
wordcount: `${countObject[property]}`,
word: property
};
connection.query("INSERT INTO wordsconnectedtoeclasscode SET ?", obj, function(error, results3) {
if (error) {
throw error;
}
console.log(results3.insertId);
});
require("console-stamp")(console, "[HH:MM:ss.l]");
const express = require("express");
const router = express.Router();
const { Database, mySQLConnectionDetails, connection } = require("../helpers/mySQL");
const { cleanseString, cleanseStringToArray, generateCountDuplication, sortValuesBykey, generateScoreArray, calculateAverage, replaceAbbreviationWithExpansion } = require("../helpers/stringFixers");
const database = new Database(mySQLConnectionDetails);
router.get("/generatewordsconnectedtoeclass", (req, res) => {
connection.query("SELECT * FROM eclasstree WHERE numberofdigits = '8'", function(error, results1) {
results1.forEach(eclassobj => {
connection.query(`SELECT itemnumber, cleanname, eclass FROM partnumbersclassified WHERE eclass = '${eclassobj.code}'`, function(error, results2) {
let stringToArray = [];
let countObject = [];
if(results2.length > 0) {
stringToArray = cleanseStringToArray(results2, "cleanname");
}
if(stringToArray.length > 0) {
countObject = generateCountDuplication(stringToArray);
for (const property in countObject) {
if (countObject.hasOwnProperty(property)) {
const obj = {
eclasscode: `${eclassobj.code}`,
wordcount: `${countObject[property]}`,
word: property
};
connection.query("INSERT INTO wordsconnectedtoeclasscode SET ?", obj, function(error, results3) {
if (error) {
throw error;
}
console.log(results3.insertId);
});
}
}
}
});
});
// res.json({});
});
});
module.exports = router;
Hello im trying to make a function that returns version numbers of a installed program on the clients machine. so far i got the version numbers but now im trying to store them into a 2d Array to use them later.
My function:
const EventEmitter = require('events');
const spawn = require('child_process').spawn;
const inst = {};
inst.check = (cmd, callback) => {
let command;
let res = [
['ffmpeg',''],
['fpcalc',''],
['eyed3','']
];
let pos;
let count = 0;
// Spwan all the comands
for (let i = 0; i < cmd.length; i++) {
pos = i;
switch (cmd[i]) {
case 'ffmpeg':
command = spawn(cmd[i], ['-version']);
break;
case 'fpcalc':
command = spawn(cmd[i], ['-v']);
break;
case 'eyed3':
command = spawn(cmd[i], ['--version']);
break;
default:
}
// Add the result to the res array
command.stdout.on('data', (data) => {
res[pos][1] = data.toString().slice(15, 20);
console.log(res[pos][1]);
});
command.stderr.on('data', (data) => {
res[pos][1] = data.toString();
console.log(res[pos][1]);
});
command.on('error', (err) => {
res[pos][1] = 'error';
throw err;
});
}
return callback(res);
};
module.exports = inst;
i call the function with this:
const cmd = ['ffmpeg', 'fpcalc', 'eyed3'];
isInstalled.check(cmd, (res) => {
console.log(res);
});
but i get following result :
[ [ 'ffmpeg', '' ], [ 'fpcalc', '' ], [ 'eyed3', '' ] ]
can someone tell me what im doing wrong ?
Fixed it my self it was an async issue
/*jshint esversion: 6 */
const spawn = require('child_process').spawn;
const asyncLoop = require('node-async-loop');
const inst = {};
inst.check = (cmds, callback) => {
let command;
let res = [];
asyncLoop(cmds, (cmd, next) => {
switch (cmd) {
case 'ffmpeg':
command = spawn(cmd, ['-version']);
break;
case 'fpcalc':
command = spawn(cmd, ['-v']);
break;
case 'eyed3':
command = spawn(cmd, ['--version']);
break;
}
// Add the result to the res array
command.stdout.on('data', (data) => {
res.push(data.toString().slice(15, 20));
next();
});
command.stderr.on('data', (data) => {
res.push(data.toString().trim());
next();
});
command.on('error', (err) => {
res.push('error');
next();
});
}, (err) => {
if (err) {
console.log(`Èrror: ${err.message}`);
return;
}
console.log(`finished: res = ${res}`);
return callback(res);
});
};
module.exports = inst;
i've folder in my node app with several json files (can be more then 10 ) and I need from validation aspects to read them and find specific property and if this property occur in more than one json file throw an error,what is the best way to do it from performance and efficiency aspects
for example my folder called plugins
and all the json are built like following
json1
{
"action": [
{
"delete": {
"path": "deleteFile",
"providedAction":"Del"
},
{
"update": {
"path": "updateFile",
"providedAction":"UPD"
}
}
]
}
this is valid json since providedAction = add is not exist in other json **
json2
{
"action": [
{
"add": {
"path": "addFile",
"providedAction":"Add"
}
}
]
}
this is not valid json since providedAction = UPD the action is already exist
JSON 3
{
"action": [
{
{
"update": {
"path": "updateFile",
"providedAction":"UPD"
}
}
]
}
I need to verify that just this json have the action "Del",if more than one json have this trow error,how its recommended to do it?
Ok, here is the code. If you don't understand something let me know and I will glad to help you!
var glob = require("glob");
var fs = require("fs");
var _inArray = function(needle, haystack) {
for(var k in haystack) {
if(haystack[k] === needle) {
return true;
}
}
return false;
}
glob("json/*.json", function(err, files) { // read the folder or folders if you want: example json/**/*.json
if(err) {
console.log("cannot read the folder, something goes wrong with glob", err);
}
var matters = [];
files.forEach(function(file) {
fs.readFile(file, 'utf8', function (err, data) { // Read each file
if(err) {
console.log("cannot read the file, something goes wrong with the file", err);
}
var obj = JSON.parse(data);
obj.action.forEach(function(crud) {
for(var k in crud) {
if(_inArray(crud[k].providedAction, matters)) {
// do your magic HERE
console.log("duplicate founded!");
// you want to return here and cut the flow, there is no point in keep reading files.
break;
}
matters.push(crud[k].providedAction);
}
})
});
});
});
JSON 1:
{"action": [
{
"delete": {
"path": "deleteFile",
"providedAction": "Del"
}
},
{
"update": {
"path": "updateFile",
"providedAction": "UPD"
}
}
]
}
JSON 2:
{
"action": [
{
"add": {
"path": "addFile",
"providedAction": "Add"
}
}
]
}
JSON 3:
{
"action": [
{
"update": {
"path": "updateFile",
"providedAction": "UPD"
}
}
]
}
Not the prettiest code I've written, but here it is:
// Require the nodejs file system library
var fs = require('fs');
var path = '/usr/local/var/jsons';
var delCounter = 0;
// Readdir reads a path and gives an array of filenames
// to the callback handleFiles.
fs.readdir(path, handleFiles);
function handleFiles (err, files) {
if (err) throw err;
var i;
var jsonFilePattern=/\.[json]+$/i;
var fileName;
var filePath;
// Tells fs to read an utf-8 file.
var fileReadOptions = {
'encoding':'utf-8'
};
for (i = 0; i < files.length; ++i) {
fileName = files[i];
// Check if the file has a .json extension
if (fileName.match(jsonFilePattern)) {
filePath = path + '/' + fileName;
// Open the file as utf-8 and call handleJsonFile back
// when done reading.
fs.readFile(filePath, fileReadOptions, handleJsonFile);
}
}
}
function handleJsonFile (err, data) {
if (err) throw err;
var dataObject = JSON.parse(data);
var i;
var action;
// Loop through all possible action.
for (i = 0; i < dataObject.action.length; ++i) {
action = dataObject.action[i];
if (action.delete &&
action.delete.providedAction &&
action.delete.providedAction === 'Del')
{
// If there is a 'Del', add it to the counter.
++delCounter;
}
}
if (delCounter > 1) {
throw new Exception('Jsons not valid.');
}
}
Something like this perhaps?, enjoy!!!
npm install glob
JSON 1
module.exports = {
"action": [{
"delete": {
"path": "deleteFile",
"action":"Del"
}
}]
}
CODE
(function() {
var glob = require("glob");
glob("path/to/*.js", function(er, files) {
if(er) return;
var x = 0;
files.forEach(function(file) {
require(file)['action'].forEach(function(act) {
if(act.delete.action && act.delete.action == "Del") x++;
});
});
if(x > 1) throw new Exception(""); // or something ja!
});
})();
5am without sleep, sorry if I commit mistakes, I want to show you the way only... not for copy paste!! xD.
Using modern syntax, reduce and spread could be of great help here:
const files = readdirSync(path);
files.reduce((acc, curr) => {
const file = JSON.parse(readFileSync(path.join(path, curr), 'utf8'));
const merged = { ...acc, ...file };
// Check for destructive merging.
if (Object.keys(file).length + Object.keys(acc).length > Object.keys(merged).length) {
throw Error('Destructive merge of JSON files.');
}
return merged;
}, {});
const fs = require('fs');
const path = require('path');
// dir path that contains all your json file
const dirPath = './something/something';
const files = fs.readdirSync(dirPath);
const arr = []
files.forEach((val, i) => {
const file = JSON.parse(fs.readFileSync(path.join(dirPath, val), 'utf8'));
arr.push(file);
})
if (arr.length === files.length) {
console.log(arr)
}
Im using nodejs and the xml2js module. I'm reading an XML file and try to emit an event after the xml is converted to an json object. My code looks like this :
var fs = require('fs'),
util = require('util'),
events = require('events'),
xml2js = require('xml2js');
var CIRCUITMODELSFILENAME = "ControlCircuitModels.xml";
var CIRCUITPARTMODELSFILENAME = "ControlCircuitParts.xml";
var circuitModels, circuitPartModels;
function ModelController() {
if (false === (this instanceof ModelController)) {
return new ModelController();
}
events.EventEmitter.call(this);
};
util.inherits(ModelController, events.EventEmitter);
ModelController.prototype.load = function (baseDir) {
var parser = new xml2js.Parser({
normalize: true,
trim: true,
explicitArray: false
});
fs.readFile(baseDir + "/" + CIRCUITMODELSFILENAME, function (err, data) {
parser.parseString(data, function (err, result) {
circuitModels = result;
console.log('circuit models loaded');
parser.reset();
fs.readFile(baseDir + "/" + CIRCUITPARTMODELSFILENAME, function (err, data) {
parser.parseString(data, function (err, result) {
circuitPartModels = result;
console.log('circuit part models loaded');
moduleReady = true;
this.emit("modelsloaded", null);
});
});
});
});
};
// public interface
exports.ModelController = ModelController;
Problem is that the scope when emitting the event is lost.
this.emit("modelsloaded", null);
this hasn't inherited the emit from EventEmitter.
How can I pass the scope to the parser.parseString function?
Thanks
Chris
Not sure if this is the best solution, bis this works (doesn't look straight foreward):
fs.readFile(baseDir + "/" + CIRCUITMODELSFILENAME, function (err, data) {
parser.parseString(data, function (err,result) {
circuitModels = result;
parser.reset();
fs.readFile(baseDir + "/" + CIRCUITPARTMODELSFILENAME, function (err, data) {
circuitPartModels = result;
console.log('circuit models loaded');
parser.parseString(data, function (err, result) {
console.log('circuit part models loaded');
this.emit("modelsloaded", null);
moduleReady = true;
circuitPartModels = result;
}.bind(this));
}.bind(this));
}.bind(this));
}.bind(this));