NodeJS Replace all values of a defined key in a json file - node.js

im trying to go from this:
{
"Level":"A",
"Group LVL2":{
"Level":"B",
"Group LVL3":{
"Level":"C"
}}}
To This
{
"Level":"C",
"Group LVL2":{
"Level":"C",
"Group LVL3":{
"Level":"C"
}}}
So i basically want to replace all values of a json key to be the same.
This a part of the code im using:
const fs = require('fs');
const fileName = './' + (Profile) + ".json";
const file = require(fileName);
const key = (Root);
file[Root] = (Value);
fs.writeFile(fileName, JSON.stringify(file, null, 2), function writeJSON(error) {
if (error) return console.log(error);
But it only replaces the Level Value of the first json group/line:
{
"Level":"THIS WILL BE REPLACED",
"Group LVL2":{
"Level":"THIS WILL NOT BE REPLACED",
"Group LVL3":{
"Level":"THIS WILL NOT BE REPLACED"
}
}
}
Hope i can find a solution to this, i count on you!
(There doesn't seem to be any beginner friendly solution online)

Below is the general solution for this kind of problem, maybe you can make it more efficient depending on your problem.
It loops through all keys of the object that are nested objects themselves, recurses for each object in the json and updates the "Level" key.
function replaceValues(obj) {
if(obj.hasOwnProperty(key))
obj[key] = value;
for (let property of Object.keys(obj)) {
if (typeof(obj[property]) === "object") {
replaceValues(obj[property]);
}
}
}
Tested on the data you provided with Value = "D"
{
"Level": "D",
"Group LVL2": {
"Level": "D",
"Group LVL3": {
"Level": "D"
}
}
}

Related

Issue while merging multiple JSON Objects

I'm trying to auto-generate a JSON object for creating a dynamic interactive list message that will be sent to users on WhatsApp.
I need a JSON object in following format:
"sections": [
{
"title": "Main Title",
"rows": [
{
"title": "row 1 title",
},
{
"title": "row 2 title",
}
]
}
]
The above code will generate a list like this
But I don't want to hard code the row's title part {"title": "row 1 title",},{"title": "row 2 title", } .
I tried using the below method where I fetch the title value from an array and merge it using spread syntax but it only returns undefined and doesn't combine all the objects.
method.js
async function genJSON() {
var arr = ['row 1', 'row 2', 'row3']
let data1, data2, d = {}
let i = 0
while (i < arr.length) {
data1 = JSON.parse(`{"title": "${arr[i]}"}`)
data2 = JSON.parse(`{"title": "${arr[i + 1]}"}`)
i++
d = { ...data1, ...data2 }
}
console.log(d)
catch (e) {
console.log(e)
}
}
genJSON()
OUTPUT:
Interactive List message: https://developers.facebook.com/docs/whatsapp/guides/interactive-messages/
How can I achieve the following output {"title": "row 1",},{"title": "row 2", ..} ? Any help or advice is appreciated.
There were two issues with your code:
You were trying to merge two dictionaries with the same keys, hence the previous key gets overwritten. Instead, you should use a JSON Array and append to it.
data2 will be undefined when i = arr.length - 1
I've fixed both the errors in the below code snippet
function genJSON() {
var arr = ['row 1', 'row 2', 'row3']
try {
let d = []
for (const row of arr) {
d.push({
title: row
})
}
console.log(d)
} catch (e) {
console.log(e)
}
}
genJSON()

Iterate object tree with arrays and objects to clean out null/undefined or empty string using node.js

So, I've found a ton of good suggestions on how to iterate over an object "tree" and filter out null, undefined, etc. which all works fine for objects and attributes.
I am trying to clean a object tree that has a ton of arrays:
"cac:Delivery": [
{
"cac:DeliveryLocation": [
{
"cbc:Name": [
{
"_": "Company Name"
}
],
"cac:Address": [
{
"cbc:StreetName": [
{
"_": "The Street 123"
}
],
"cbc:AdditionalStreetName": [
{
"_": null
}
],
"cbc:CityName": [
{
"_": "The City"
}
],
"cbc:PostalZone": [
{
"_": ""
}
],
"cac:Country": [
{
"cbc:IdentificationCode": [
{
"_": ""
}
]
}
]
}
]
}
]
}
]
The above sample is a snippet of the full message and why it looks like this is because the original is a UBL XML message that we run xml2js on to transform it from XML to JSON.
We then need to run some other mappings and extraction of values on the tree. The next step of the flow won't accept any null, undefined or empty string as values.
The problem I have a that I can't figure out any nifty way of traversing the tree with the arrays and clean out the tree (=remove the "empty" attributes).
In the sample, cleaning out cbc:IdentificationCode will then of course make cac:Country to be empty in turn...
There are hundreds of "groups" that I need to "clean" so I need to come up with something dynamic and it is also important that the order of attributes are kept...
The above should result in:
"cac:Delivery": [
{
"cac:DeliveryLocation": [
{
"cbc:Name": [
{
"_": "Company Name"
}
],
"cac:Address": [
{
"cbc:StreetName": [
{
"_": "The Street 123"
}
],
"cbc:CityName": [
{
"_": "The City"
}
]
}
]
}
]
}
]
EDIT:
The data is based upon UBL JSON representation: https://docs.oasis-open.org/ubl/UBL-2.1-JSON/v2.0/cnd01/UBL-2.1-JSON-v2.0-cnd01.html
Various samples can be found here: https://docs.oasis-open.org/ubl/UBL-2.1-JSON/v2.0/cnd01/json/
(I am currently working on the "Invoice" message)
EDIT2:
Figured to share to "iterator" I came up with that is traversing the entire tree and handles each Object/Array/Attribute:
function iterate(obj) {
Object.entries(obj).forEach(([key, value]) => {
console.log('KEY:', key);
if (Array.isArray(obj[key])) {
console.log('ARRAY');
obj[key].forEach((k) => iterate(k));
} else if (typeof obj[key] === 'object') {
console.log('OBJECT');
if (obj[key]) {
iterate(obj[key]);
}
} else {
console.log('Key / Value:', key, value);
if (!value) {
console.log('THIS IS AN EMPTY VALUE!');
}
}
});
}
Well, maybe not the most elegant of solutions but after a few hours of pondering this I solved it using lodash _.set() which can create a object tree from paths... I called my function deepClean() and this now returns an object without any nullish values (but I do want to keep 0's):
function iterate(obj, arrObj, path = '') {
Object.entries(obj).forEach(([key, value]) => {
// Construct the path to the object/array that we are currently looking at
const newPath = `${path}${path ? '.' : ''}['${key}']`;
if (Array.isArray(obj[key])) {
// If it is an array we have to add the [index] to the path as well, then iterate over the array
obj[key].forEach((k, index) => iterate(k, arrObj, `${newPath}[${index}]`));
} else if (typeof obj[key] === 'object') {
// If it's an object, and the object has any child/value iterate again
if (obj[key]) {
iterate(obj[key], arrObj, newPath);
}
} else {
// If this is a "value" push it to the Array
arrObj.push([`${path}.${key}`, value]);
}
});
}
const deepClean = (obj) => {
// We need to clean the whole object tree and remove any array/object/key that are "nullish"
// however, we must keep values as zero (number) as e.g. VAT can be zero
const arrObj = [];
const newObj = {};
// Call itarate() to loop through the entire tree recursivly and build an array as [path-to-object, value]
iterate(obj, arrObj);
arrObj.forEach((o) => {
// Start creating the new cleaned object from the values/paths using lodash _.set()
if (typeof o[1] === 'number' || o[1]) {
_.set(newObj, o[0], o[1]);
}
});
return newObj;
};
ElasticObject is a wrapper for objects that adds array methods to objects. I would use that and than its filter method.

Parsing JSON files in nodejs

I want to parse this JSON data to a file like this :
JSON
{
"nodes": [
{"id": 1, "name" : "a", "radius" :0.5, "angle" : 2.64159265359},
{"id": 2, "name" : "b", "radius" : 0.6, "angle" : 3.64159265359}
],
"links": [
{"source": "a", "target": "b", "delay": "10ms"}
]
}
File :
[nodes]
a: _ radius=0.5 angle=2.64159265359
b: _ radius=0.6 angle=3.64159265359
[links]
a:b delay=10ms
So far my code is just reading the JSON file
const fs = require('fs');
data = JSON.parse(fs.readFileSync("topo.json","utf-8"));
for (node in data)
{
for (link in data[node])
{
console.log(data[node][link]);
}
}
How can I get those values saved and create a new file having those values in them ?
You did not specify what file type you want to use, so I went with a simple .txt file.
The only small Issue with the code posted, is that these are arrays, so you have to loop a bit differently over them. Apart from that simply write the data into placeholders in your format string and append it to a global object that will be written to the file. Then you should be good to like that:
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('topo.json','utf-8'));
let textFileContent = '';
textFileContent += '[nodes]\n';
data.nodes.forEach(node => {
textFileContent += `${node.name}: _ radius=${node.radius} angle=${node.angle}\n`;
});
textFileContent += '[links]\n';
data.links.forEach(link => {
textFileContent += `${link.source}:${link.target} delay=${link.delay}\n`;
});
fs.writeFile('parsed.txt', textFileContent, function(err) {
if(err) {
return console.log(err);
}
});
Note that this could probably be done more elegant and it won`t scale very well, if your JSON is more complex, than whats shown in the sample...

Using modified mongoose-uuid2 breaks save operation [duplicate]

When using the library mongoose-uuid, I am able to setup UUID types for my schemas, so when I read the data it is in string (utf-8) format and when I save the data it is in UUID ObjectID BSON type 4 format. This works great with top level or flat direct values and ref definitions in my schema. However, when I have a UUID's in an array of ref's in a schema, the array saves to the database correctly, However when it is presented it is in its raw type. Based on the example below you can see scope_id is presented in the right format but the entitlements are not.
Here are the versions I am using:
mongoose-uuid - 2.3.0
mongoose - 5.5.11
I have tried modifying the library (mongoose-uuid) by changing the getter and converting the value, however, when I do so, it works when presenting but fails when it saves to the database. This is most likely due to the fact that the value is converted or casted before saving to the database.
Here is an example schema
{
"code": {
"type": String,
"required": true
},
"scope_id": {
"type": mongoose.Types.UUID,
"ref": "scopes"
},
"entitlements": [{
"type": mongoose.Types.UUID,
"ref": "entitlements"
}]
}
Example actual response
{
"entitlements": [
"zMihi1BKRomM1Q41p7hgLA==",
"ztOYL7n1RoGA6aoc0TcqoQ=="
],
"code": "APPUSR",
"scope_id": "b8f80c82-8325-4ffd-bfd7-e373a90e7c45",
"id": "32e79061-e531-45ad-b934-56811e2ad713"
}
Expected Response
{
"entitlements": [
"ccc8a18b-504a-4689-8cd5-0e35a7b8602c",
"ced3982f-b9f5-4681-80e9-aa1cd1372aa1"
],
"code": "APPUSR",
"scope_id": "b8f80c82-8325-4ffd-bfd7-e373a90e7c45",
"id": "32e79061-e531-45ad-b934-56811e2ad713"
}
As mentioned above, the code does work but breaks another part of the code. I found a solution that corrects this:
It is a slight amendment to the code above
SchemaUUID.prototype.cast = function (value, doc, init) {
console.log("cast", value, doc, init)
if (value instanceof mongoose.Types.Buffer.Binary) {
if (init && doc instanceof mongoose.Types.Embedded) {
return getter(value);
}
return value;
}
if (typeof value === 'string') {
var uuidBuffer = new mongoose.Types.Buffer(uuidParse.parse(value));
uuidBuffer.subtype(bson.Binary.SUBTYPE_UUID);
return uuidBuffer.toObject();
}
throw new Error('Could not cast ' + value + ' to UUID.');
};
This alternate version of the code allows for updates such as POST and PATCH to be applied.
As per my observation, if you change the below function in mongoose, it works fine
SchemaUUID.prototype.cast = function (value, doc, init) {
console.log("cast", value, doc, init)
if (value instanceof mongoose.Types.Buffer.Binary) {
if (init) {
return getter(value);
} else {
return value;
}
}
if (typeof value === 'string') {
var uuidBuffer = new mongoose.Types.Buffer(uuidParse.parse(value));
uuidBuffer.subtype(bson.Binary.SUBTYPE_UUID);
return uuidBuffer.toObject();
}
throw new Error('Could not cast ' + value + ' to UUID.');
};
Basically when you save objects init is false and when its initiated init is true

Duplicate an object in array in mongoose

I want to duplicate an object in array in mongoose.
For example, if there is a object which projectName is "a", I want to create a complete same one, but the name is called "a duplicated".
I tried to the following code:
project.find({
"logininfo.username": username,
}, (err, users) => {
...
var user= users[0];
var dproject;
for(var i in user.projects){
if(user.projects[i].projectName === projectName)
{
dproject = user.projects[i];
break;
}
}
dproject.projectName += " duplicated";
dproject._id = new mongoose.Types.ObjectId();
user.projects.push(dproject)
projects.save((err, user) => {
...
However, this function will also change the previous object, which creates a completely same object (both names change to "a duplicated"), these two objects have the same _id.
How can I duplicate the object but keep the projectName and _id different?
Use JSON.parse(JSON.stringify(object)) to deep copy. It will make a copy but not a reference.
for (var i in projects.projects) {
if (projects.projects[i].projectName === projectName) {
dproject = JSON.parse(JSON.stringify(projects.projects[i])); //deep copy
break;
}
}
dproject._id = new mongoose.Types.ObjectId();
dproject.projectName += " duplicated";
projects.projects.push(dproject)

Resources