Different actions based upon JSON value in Node - javascript

A perplexing question. I am writing a node based command line tool that has a source json file, and then will take a changes JSON file (i.e. add, update, delete, etc) and I need to basically make the operation into a new JSON file and output to a new file. Not as simple as it sounds. With no command line arguments, etc. you would need to have a directive field in the JSON like so?
The app would work like this:
$ myapp source.json changes.json newfile.json
{
"action": "addRecord",
"payload": {
"id": "1",
"name": "James Hetfield",
"guitar": "More Beer"
}
},
"action": "deleteRecord",
"payload": {
"id": "3",
"name": "Dave Mustaine",
"guitar": "Ole Faithful"
}
}
My JSON structure is probably wrong as well, but wondering how you would use JSON.parse, JSON.stringify to read the file in with the fs library and actually make actions happen when identifying action and then execute a CRUD like statement with payload
Here is what I have so far:
#!/usr/bin/env node
// using fs for parsing for small example
const fs = require('fs');
// We do not simply require the file due to scaling.
// Large file will cause event locking. To handle
// even greater files we would use Node streams.
const file = './changes.json';
// target filename for output
const target = 'output.json';
fs.readFile(file, 'utf8', function(err, data) {
if (err) {
console.log('Error' + err);
return;
}
let obj = JSON.parse(data, (key, value) => {
if (key === 'action') {
if (value === 'addSong') {
return value = "Song Added";
}
if (value === "addPlaylist") {
return value = "Playlist added";
}
if (value === "deletePlaylist") {
return value = "Playlist deleted";
}
}
return value;
});
console.dir(obj);
});
fs seems to just read through the file and pick up the last value read. Not good. Wondering how to do the compare and possibly structure the JSON to make the action happen and then append? or transform the JSON into a new file with the update. Stuck.

Related

How can I insert data from a JSON to a const variable in NodeJS for using an API?

I'm currently working on a NodeJS project, this takes data from a JSON and then use it to take weather stuff form an API, after that I want to save it to a DB, I already asked about it and that question helped me fixing some problems but now I have some others, I'm sending the data to a constant but the issue is that I don't know why am I getting an error in the JSON Parse, I want to use the lat and lon from the JSON (I have like a hundred data coords) and insert it into the const, any help would help, This is the error I'm getting
Successful connection
[]
undefined:1
^
SyntaxError: Unexpected token in JSON at position 0
at JSON.parse (<anonymous>)
here is my function that takes data from JSON and gets data from the API:
async function calcWeather() {
fs.readFile("./json/data.json","utf8", function (err, data) {
if(err) throw err;
data2 = JSON.parse(data);
console.log(typeof data2);
for (let item of data2) {
let base = `https://api.openweathermap.org/data/2.5/weather?lat=${item.latjson}&lon=${item.lonjson}&appid=${api_key}&units=metric&lang=sp`;
fetch(base)
.then((responses) => {
return responses.json();
})
.then((data) => {
var myObject = {
Id_Oficina: item.IdOficina,
Humedad: data.main.humidity,
Nubes: data.clouds.all,
Sensacion: data.main.feels_like,
Temperatura: data.main.temp,
Descripcion: data.weather.description,
};
// validation and saving data to array
if (myObject.Temperatura < 99) {
lstValid.push(myObject);
}
});
}
});
console.log(lstValid);
}
here is the JSON where I take the data:
[
{
"latjson": 1,
"lonjson": 1,
"IdOficina": "1"
},
{
"latjson": 2,
"lonjson": 2,
"IdOficina": "2"
}
]
I think the issue is in the parse, but I don't get what I am doing wrong
Since you are reading the file with fs.readFile, you are getting a string and not a JavaScript object. You would need to parse it entirely in order to be able to manipulate the content (you seem to be parsing the first character only):
const fs = require('fs')
let rawdata = fs.readFileSync('./data.json')
let data = JSON.parse(rawdata)
Personally, I think it's way easier to require it (no need to use fs):
const jsonData = require('./json/data.json')
async function calcWeather() {
for (let item of jsonData) {
// ...
}
}

fs readFile code in Node.js somehow broke

I have a simple web application that I am using with Node.js and Express. This is my package structure:
The contents of my questions.json file are as follows:
[
{
"question": "What is your favorite color?",
"id": 1
},
{
"question": "How old are you?",
"id": 2
},
]
And operations.json contains this:
var fs = require('fs');
const questions = 'public/questions.json';
class Operations{
constructor() {
fs.readFile(questions, (err, data) => {
if (err) throw err;
this.questions = JSON.parse(data);
});
}
findID(id) {
for (let key in this.questions) {
if (this.questions[key].id == id) {
console.log('found it!');
}
}
console.log("can't find it!...");
}
}
var test = new Operations();
test.findID(1);
This code used to work before but now for some odd reason, it is broken. The output of test.findID(1); Always returns can't find it... And I cannot figure out why. If I do a console.log(this.questions) outside of my constructor, it always prints undefined, but if I were to console.log(JSON.parse(data)) inside the callback function of the fs.readFile it will display the contents of the file.
Probably test.findID(1) is being executed before the actual IO reading happens, so at that moment, questions is undefined.
Try using fs.readFileSync instead of fs.readFile. This should be actually be fine, as you are still within the constructor of the object.

How to export/save updated d3.js v4 tree json data string

I'm using the following code:
https://bl.ocks.org/adamfeuer/042bfa0dde0059e2b288
And am loading a very simple json string to create the tree:
{
"name": "flare",
"children": [{
"name": "analytics"
}, {
"name": "animate"
}]
}
So what I'm trying to figure out is that after I add a new child node to the "flare" node (for example), how can I create an updated json string in order to save the newly added node?
An example of the updated json after adding a new node would be like so:
{
"name": "flare",
"children": [{
"name": "analytics"
}, {
"name": "animate"
}, {
"name": "NEW NODE"
}]
}
Is there some built in function for this that I am not finding? Or would a custom function have to be built? And if I need a custom function could somebody please point me in the right direction to do so? Thank you very much!
I propose this solution that is not perfect and which deserves improvements but that works,
it will help you get started.
All the code below is added at the end of the update function in the dndTree.js file.
console.log(root); //root contains everything you need
const getCircularReplacer = (deletePorperties) => { //func that allows a circular json to be stringified
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if(deletePorperties){
delete value.id; //delete all properties you don't want in your json (not very convenient but a good temporary solution)
delete value.x0;
delete value.y0;
delete value.y;
delete value.x;
delete value.depth;
delete value.size;
}
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
var myRoot = JSON.stringify(root, getCircularReplacer(false)); //Stringify a first time to clone the root object (it's allow you to delete properties you don't want to save)
var myvar= JSON.parse(myRoot);
myvar= JSON.stringify(myvar, getCircularReplacer(true)); //Stringify a second time to delete the propeties you don't need
console.log(myvar); //You have your json in myvar
Now that you have your json, you can either :
Download your new tree.json file :
function download(content, fileName, contentType) {
var a = document.createElement("a");
var file = new Blob([content], {
type: contentType
});
a.href = URL.createObjectURL(file);
a.download = fileName;
a.click();
}
download(myvar, 'tree.json', 'text/plain');
Or you could directly write in your file.
An example with node.js :
var fs = require('fs');
fs.writeFile("tree.json", myvar, function(err) {
if (err) {
console.log(err);
}
});
Check this for more informations to save a file: How do I save JSON to local text file

How to write a postman test to compare the response json against another json?

I have the below json response after running a postMan test of a Rest API:
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
Now I would like to compare the above json against a predefined json. Say, its the same as above.
How can I compare two jsons via the Postman test?
I had a similar problem to solve except that my JSON also contained an array of objects. I used the following technique that can be modified to deal with the simple array of strings in your question.I created an array of global functions called "assert", which contained helper functions such as "areEqual" and "areArraysOfObjectsEqual" and saved these under the "Tests" tab at a top folder level of my tests.
assert = {
areEqual: (actual, expected, objectName) => {
pm.test(`Actual ${objectName} '` + actual + `' matches Expected ${objectName} '` + expected + `'`, () => {
pm.expect(_.isEqual(actual, expected)).to.be.true;
});
},
areArraysOfObjectsEqual: (actual, expected, objectName) => {
if (!_.isEqual(actual, expected)) {
// Arrays are not equal so report what the differences are
for (var indexItem = 0; indexItem < expected.length; indexItem++) {
assert.compareArrayObject(actual[indexItem], expected[indexItem], objectName);
}
}
else
{
// This fake test will always pass and is just here for displaying output to highlight that the array has been verified as part of the test run
pm.test(`actual '${objectName}' array matches expected '${objectName}' array`);
}
},
compareArrayObject: (actualObject, expectedObject, objectName) => {
for (var key in expectedObject) {
if (expectedObject.hasOwnProperty(key)) {
assert.areEqual(expectedObject[key], actualObject[key], objectName + " - " + key);
}
}
}
};
Your "Pre-request Script" for a test would set your expected object
const expectedResponse =
{
"id": "3726b0d7-b449-4088-8dd0-74ece139f2bf",
"array": [
{
"item": "ABC",
"value": 1
},
{
"item": "XYZ",
"value": 2
}
]
};
pm.globals.set("expectedResponse", expectedResponse);
Your Test would test each item individually or at the array level like so:
const actualResponse = JSON.parse(responseBody);
const expectedResponse = pm.globals.get("expectedResponse");
assert.areEqual(
actualResponse.id,
expectedResponse.id,
"id");
assert.areArraysOfObjectsEqual(
actualResponse.myArray,
expectedResponse.myArray,
"myArrayName");
This technique will give nice "property name actual value matches expected value" output and works with arrays of objects being part of the JSON being compared.
Update:
To test your array of strings "GlossSeeAlso", simply call the supplied global helper method in any of your tests like so:
assert.compareArrayObject(
actualResponse.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso,
expectedResponse.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso,
"glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso");
Primitive types in JSON key value pairs can be tested like so:
assert.areEqual(
actualResponse.glossary.title,
expectedResponse.glossary.title,
"glossary.title");
I got it after a while. Add test into your request and use Runner to run all your requests in the collection.
Postman info: Version 7.10.0 for Mac.
Test scripts:
pm.test("Your test name", function () {
var jsonData = pm.response.json();
pm.expect(jsonData).to.eql({
"key1": "value1",
"key2": 100
});
});
You can paste this code into your collection or single request tests tab.
What this code do is to save the request into a global variable with a key for that request. You can change your enviroment and hit the same request and if the response are different the test will fail.
const responseKey = [pm.info.requestName, 'response'].join('/');
let res = '';
try {
res = JSON.stringify(pm.response.json());
} catch(e) {
res = pm.response.text();
}
if (!pm.globals.has(responseKey)) {
pm.globals.set(responseKey, res);
} else {
pm.test(responseKey, function () {
const response = pm.globals.get(responseKey);
pm.globals.unset(responseKey);
try {
const data = pm.response.json();
pm.expect(JSON.stringify(data)).to.eql(response);
} catch(e) {
const data = pm.response.text();
pm.expect(data).to.eql(response);
}
});
}
Hope this help.
You can write javascript code inside Tests tab of Postman. Just write simple code to compare and check result in Tests.
var serverData = JSON.parse(responseBody);
var JSONtoCompare = {}; //set your predefined JSON here.
tests["Body is correct"] = serverData === JSONtoCompare;
Looks like the same question asked at POSTMAN: Comparing object Environment variable with response's object which also lists a solution that works, which is to use JSON.stringify() to turn the objects into strings and then compare the strings.
Came across this issue when migrating from a legacy API to a new one and wanting to assert the new API is exactly the same as the old under different scenarios
For context this clones params of the original get request to the legacy endpoint and validates both match up
LEGACY_API_URL should be defined in the environment and the Request is going to the new API
const { Url } = require('postman-collection');
// Setup the URL for the Legacy API
const legacyRequestUrl = new Url({ host: pm.variables.replaceIn("http://{{LEGACY_API_HOST}}/blah")});
// Add All Parameters From the Source Query
legacyRequestUrl.addQueryParams(pm.request.url.query.all());
// Log out the URL For Debugging Purposes
console.log("URL", legacyRequestUrl.toString());
pm.sendRequest(legacyRequestUrl.toString(), function (err, response) {
pm.test('New API Response Matches Legacy API Response', function () {
// Log Out Responses for Debugging Purposes
console.log("New API Response", pm.response.json())
console.log("Legacy API Response", response.json())
// Assert Both Responses are Equal
pm.expect(_.isEqual(pm.response.json(), response.json())).to.be.true
});
});
Link to an example collection
https://www.getpostman.com/collections/4ff9953237c0ab1bce99
Write JavaScript code under 'Tests' section. Refer below link for more info.
Click Here

How to check in NodeJS if json file already got specific data

I'm trying to make a CRUD operations with NodeJS. But i don't know how to check if JSON file already got the specific part and then update only needed object and not overwrite the other data or add the new data if there is no record of it.
this is what i have so far ( right now the insert operation overwrites the whole file and leaves it with only inserted data ) :
JSON :
JSON:
{
"id": 1,
"name": "Bill",
},
{
"id": 2,
"name": "Steve",
},
Code :
var operation = POST.operation; // POST request comes with operation = update/insert/delete
if (operation == 'insert') {
fs.readFile("data.json", "utf8", function (err) {
var updateData = {
id: POST.id,
name: POST.name,
}
var newUser = JSON.stringify(updateData);
fs.writeFile("data.json", newUsers, "utf8");
console.log(err);
})
}
else if (operation == 'update') {
fs.readFile("data.json", "utf8", function (err) {
})
}
else if (operation == 'delete') {
fs.readFile("data.json", "utf8", function (err) {
})
}
else
console.log("Operation is not supported");
The most examples that i've found were with Database and Express.js. So they didn' really help much.
Sorry , i'm a newbie.
So first off, that is not valid JSON (unless this is only part of the file). You will need to wrap that whole list into an array for it to be valid JSON (You can check if your JSON is valid here)
If you go with a structure like this:
[
{
"id": 1,
"name": "Bill",
},
{
"id": 2,
"name": "Steve",
},
]
I think the easiest way to check if the ID already exists will be to read the JSON in as an array and check if the ID has already been assigned. Something like this:
var json = require('/path/to/data.json'); // Your object array
// In the if (operation == 'insert') block
var hadId = json.some(function (obj) {
return obj.id === POST.ID;
});
if (hasId) {
// Do something with duplicate
}
json.push({
id: POST.id,
name: POST.name
});
// Write the whole JSON array back to file
More on the array.some function
So basically you will be keeping the whole JSON file in memory (in the json array) and when you make a change to the array, you write the whole updated list back to file.
You may run into problems with this if that array gets very large, but at that point I would recommend looking into using a database. Mongo (all be it not the greatest DB in the world) is fairly easy to get setup and to integrate with JavaScript while playing and experimenting.
I hope this helps!
Good luck

Categories

Resources