How to use multiple JSON objects for single NodeJS/Jade Merge - javascript

Given the following setup code (loosely realistic)
default.js (used by config.js for loading base configurations)
{
"templateData": {
"corp": {
"corpName": "Company",
"DepartmentOne": {
"name": "DepartmentOne",
"phone": "1-800-555-555",
"email": "departmentone#company.com"
},
"address": {
"main": {
"addressLine1": "Somwhere",
"city": "SomeTown",
"stateShort": "SState",
"stateLong": "SomeState",
"zipCodeShort": "Zippy"
}
},
"urls": {
"company": {
"corporate": {
"site": "https://company.com/",
"logo": "http://sites.company.com/images/logo.png",
"altText" : "Company Corporate Logo"
},
"facebook": {
"site": "https://www.facebook.com/company",
"icon": "http://sites.company.com/images/facebook.png",
"altText" : "Company Facebook Page"
},
"twitter": {
"site": "https://twitter.com/company",
"icon": "http://sites.company.com/images/twitter.png",
"altText" : "Company Twitter Feed"
},
"youtube": {
"site": "https://www.youtube.com/company",
"icon": "http://sites.company.com/images/youtube.png",
"altText" : "Company YouTube Channel"
}
}
},
"currentYear": "2015",
"corpWebSiteName": "Company.com"
}
}
}
test01.js (main node code)
var fs = require('fs');
var bunyan = require('bunyan');
var jade = require('jade');
var config = require('config');
var restify = require('restify');
var log = bunyan.createLogger({src: false, name: "emailTemplateMerger"});
var html = '';
var corpConfig = config.get('templateData');
var emailData = { 'emailAddress' : 'nonya#bidness.com',
'firstName' : 'nonya',
'lastName' : 'bidness'
}
var miscData = { 'billingDate' : '2015-08-01',
'accountType' : 'new',
'discountTypes' : {
'primary' : 'Coupon20',
'bonus' : 'First30Days',
'standard' : 'freeShipping'
}
}
fs.readFile('./emailTemplates/test01.jade', 'utf-8', function(error, source){
var template = jade.compile(source);
html = template(corpConfig)
console.log(html);
});
Jade Template:
html
head
body
p.
Hello #{emailData.firstName},
p.
Welcome to #{corp.corpName}'s #{DepartmentOne.name}.
p.
Your next bill will be sent on #{miscData.billingDate} for your #{miscData.accountType}.
p.
Thank you
Problem: Determining an efficient method of merging the config data and the 2 local datasets (which will be passed in via REST) into the Jade template.
Since the data has many levels of nesting, a direct merge can be complex and possibly error prone depending on the data passed in, is there anyway to pass Jade multiple, separate datasets and defer the merging to the Jade engine?
I've tried multiple passes, but a single pass of the Jade merge removes all tags from the template so that didn't work out. I haven't figured out anyway to chain the results.

You could create a top level context object like this:
var context = {
corp: corpConfig,
email: emailData,
misc: miscData
};
....
var html = template(context);
And then change the template references to something like this
html
head
body
p.
Hello #{context.email.firstName},
p.
Welcome to #{context.corp.corpName}'s #{context.misc.DepartmentOne.name}.

Related

Editing JSON files in NodeJS and DiscordJS

Right, so I am trying to wrap my head around editing (appending data) to a JSON file.
The file (users.json) looks like this:
{
"users": {
"id": "0123456789",
"name": "GeirAndersen"
}
}
Now I want to add users to this file, and retain the formatting, which is where I can't seem to get going. I have spent numerous hours now trying, reading, trying again... But no matter what, I can't get the result I want.
In my .js file, I get the data from the json file like this:
const fs = require('fs').promises;
let data = await fs.readFile('./test.json', 'utf-8');
let users = JSON.parse(data);
console.log(JSON.stringify(users.users, null, 2));
This console log shows the contents like it should:
{
"id": "0123456789",
"name": "GeirAndersen"
}
Just to test, I have defined a new user directly in the code, like this:
let newUser = {
"id": '852852852',
"name": 'GeirTrippleAlt'
};
console.log(JSON.stringify(newUser, null, 2));
This console log also shows the data like this:
{
"id": "852852852",
"name": "GeirTrippleAlt"
}
All nice and good this far, BUT now I want to join this last one to users.users and I just can't figure out how to do this correctly. I have tried so many version and iterations, I can't remember them all.
Last tried:
users.users += newUser;
users.users = JSON.parse(JSON.stringify(users.users, null, 2));
console.log(JSON.parse(JSON.stringify(users.users, null, 2)));
console.log(users.users);
Both those console logs the same thing:
[object Object][object Object]
What I want to achieve is: I want to end up with:
{
"users": {
"id": "0123456789",
"name": "GeirAndersen"
},
{
"id": "852852852",
"name": "GeirTrippleAlt"
}
}
When I get this far, I am going to write back to the .json file, but that part isn't an issue.
That's not really a valid data structure, as you're trying to add another object to an object without giving that value a key.
I think what you're really looking for is for 'users' to be an array of users.
{
"users": [
{
"id": "0123456789",
"name": "GeirAndersen"
},
{
"id": "852852852",
"name": "GeirTrippleAlt"
}
]
}
You can easily create an array in JS and the push() new items into your array. You JSON.stringify() that with no issue.
const myValue = {
users: []
};
const newUser = {
'id': '0123456789',
'name': "GeirAndersen'
};
myValue.users.push(newUser);
const strigified = JSON.stringify(myValue);

How to store Exception/Error from Azure function js?

I have created an Azure function to save data in SQL database from Iot Hub that is working fine, Now I want to save Exception and Error to Azure storage Table so for that I have added try{ } catch(err){} but that is not working. please correct me. Thanks!
my function is here
module.exports = function (context, iotHubMessage) {
try {
var strMsg = JSON.stringify(iotHubMessage);
context.log('Message received: ' + strMsg);
var ob1 = { "employee_idw": 444, "last_name": "Teller", "first_name": "Saara", "age": 34, "salary": 87000 };
//I misspelled 'employee_idw' to generate error
var ob2 = { "employee_id": 555, "last_name": "Teller", "first_name": "Saara", "age": 31, "salary": 87000 };
ob1.EventProcessedUtcTime = new Date;
ob2.EventProcessedUtcTime = new Date;
var arr = [];
arr.push(ob1);
arr.push(ob2);
context.bindings.outputTable = arr;
context.done();
} catch (err) {
context.log('CCC Error' + err); // even can not see this message in log
context.bindings.error= { "partitionKey": partitionKey, "rowKey": rowKey, "data": err };
}
};
see this is JSON file
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "myEventHubMessage",
"path": "myeventhub",
"consumerGroup": "$Default",
"connection": "PBCorIOTHub_events_IOTHUB",
"cardinality": "many",
"direction": "in"
},
{
"type": "apiHubTable",
"name": "outputTable",
"dataSetName": "default",
"tableName": "employees",
"connection": "sql_SQL",
"direction": "out"
},
{
"type": "table",
"name": "error",
"tableName": "dddtTest",
"connection": "cccteststr_STORAGE",
"direction": "out"
}
],
"disabled": false
}
Are you using Azure SQL or Azure table storage to store the data? From your code it looks like you are using Azure table storage. The reason i ask is because a changed property name would not cause an error in function. Instead the table storage would create a new property with misspelled name.
Like Mikhail suggested the to store an error caused inside of a function all you have to do is create another output binding and assign the exception to it.
However not all exceptions occur inside of a function context. For example an error in function.json configuration could cause a error connecting to storage. This would cause function execution to fail outside of function code context. Azure functions has direct integration with Application Insights and can help monitor what you are looking for. Here is a blog post that can shows how to configure Application Insights.
https://blogs.msdn.microsoft.com/appserviceteam/2017/04/06/azure-functions-application-insights/

How to export or convert JSON to Excel in AngularJS?

I'm extracting an array with 4 objects and each object has an array inside, from my kendo charts datasource, on my Angular project.
The data inside each sub-object varies in size, but it always includes a timestamp, and 1-5 value fields.
I need to export this array to an Excel file (.xls or .xlsx NOT CSV).
So far I managed to download the JSON as a file on its own (both .json and unformatted .xls).
I'd like for each object to be a book and in that book to have a formatting that has the timestamp in the first column, value 1 in another, and so on. The header for the columns should be timestamp, value1 name, etc (I'm translating these on the ui according to user preferences).
How can I build this type of formatted .xls file using angular? I don't know a particular good library for this, that is clear on how to use it in Angular.
Following Nathan Beck's link sugestion, I used AlaSQL. I'm getting correctly formatted columns, just need to adapt my array to have multiple worksheets.
The way we integrate alaSQL into our Angular project is by including the alasql.min.js and xlsx.core.min.js.
Then we call the alasql method in our function
$scope.export = function(){
var arrayToExport = [{id:1, name:"gas"},...];
alasql('SELECT * INTO XLSX("your_filename.xlsx",{headers:true}) FROM ?', arrayToExport);
}
EDIT: Solved the multiple worksheets issues as well. Keep in mind that when using the multiple worksheet method, you have to remove the asterisk and replace the headers: true object in the query with a question mark, passing the options in a separate array. So:
var arrayToExport1 = [{id:1, name:"gas"},...];
var arrayToExport2 = [{id:1, name:"solid"},...];
var arrayToExport3 = [{id:1, name:"liquid"},...];
var finalArray = arrayToExport1.concat(arrayToExport2, arrayToExport3);
var opts = [{sheetid: "gas", headers: true},{sheetid: "solid", headers: true},{sheetid: "liquid", headers: true}];
alasql('SELECT INTO XLSX("your_filename.xlsx",?) FROM ?', [opts, finalArray]);
You can use the XLSX library to convert JSON into XLS file and Download. Just create a service for your AngularJS application then call it as service method having below code.
I found this tutorial having JS and jQuery code but we can refer this code to use in AngularJS
Working Demo
Source link
Method
Include library
<script type="text/javascript" src="//unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
JavaScript Code
var createXLSLFormatObj = [];
/* XLS Head Columns */
var xlsHeader = ["EmployeeID", "Full Name"];
/* XLS Rows Data */
var xlsRows = [{
"EmployeeID": "EMP001",
"FullName": "Jolly"
},
{
"EmployeeID": "EMP002",
"FullName": "Macias"
},
{
"EmployeeID": "EMP003",
"FullName": "Lucian"
},
{
"EmployeeID": "EMP004",
"FullName": "Blaze"
},
{
"EmployeeID": "EMP005",
"FullName": "Blossom"
},
{
"EmployeeID": "EMP006",
"FullName": "Kerry"
},
{
"EmployeeID": "EMP007",
"FullName": "Adele"
},
{
"EmployeeID": "EMP008",
"FullName": "Freaky"
},
{
"EmployeeID": "EMP009",
"FullName": "Brooke"
},
{
"EmployeeID": "EMP010",
"FullName": "FreakyJolly.Com"
}
];
createXLSLFormatObj.push(xlsHeader);
$.each(xlsRows, function(index, value) {
var innerRowData = [];
$("tbody").append('<tr><td>' + value.EmployeeID + '</td><td>' + value.FullName + '</td></tr>');
$.each(value, function(ind, val) {
innerRowData.push(val);
});
createXLSLFormatObj.push(innerRowData);
});
/* File Name */
var filename = "FreakyJSON_To_XLS.xlsx";
/* Sheet Name */
var ws_name = "FreakySheet";
if (typeof console !== 'undefined') console.log(new Date());
var wb = XLSX.utils.book_new(),
ws = XLSX.utils.aoa_to_sheet(createXLSLFormatObj);
/* Add worksheet to workbook */
XLSX.utils.book_append_sheet(wb, ws, ws_name);
/* Write workbook and Download */
if (typeof console !== 'undefined') console.log(new Date());
XLSX.writeFile(wb, filename);
if (typeof console !== 'undefined') console.log(new Date());
Angular directive for exporting and downloading JSON as a CSV. Perform bower install ng-csv-download. Run in plunkr
var app = angular.module('testApp', ['tld.csvDownload']);
app.controller('Ctrl1', function($scope, $rootScope) {
$scope.data = {};
$scope.data.exportFilename = 'example.csv';
$scope.data.displayLabel = 'Download Example CSV';
$scope.data.myHeaderData = {
id: 'User ID',
name: 'User Name (Last, First)',
alt: 'Nickname'
};
$scope.data.myInputArray = [{
id: '0001',
name: 'Jetson, George'
}, {
id: '0002',
name: 'Jetson, Jane',
alt: 'Jane, his wife.'
}, {
id: '0003',
name: 'Jetson, Judith',
alt: 'Daughter Judy'
}, {
id: '0004',
name: 'Jetson, Elroy',
alt: 'Boy Elroy'
}, {
id: 'THX1138',
name: 'Rosie The Maid',
alt: 'Rosie'
}];
});
<!DOCTYPE html>
<html ng-app="testApp">
<head>
<meta charset="utf-8" />
<title>Exporting JSON as a CSV</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script src="csv-download.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div>Using an Angular directive for exporting JSON data as a CSV download.</div>
<div ng-controller="Ctrl1">
<h2>All Attributes Set</h2>
<csv-download
filename="{{data.exportFilename}}"
label="{{data.displayLabel}}"
column-header="data.myHeaderData"
input-array="data.myInputArray">
</csv-download>
<hr />
<h2>Only Required Attribute Set</h2>
<h3>Optional Attributes Default</h3>
<csv-download
input-array="data.myInputArray">
</csv-download>
</div>
</body>
</html>

Update object with given ID embed in array without restructuring Mongo database

I've got the following document named "clients" which includes id, name and list of projects (array of objects):
{
"_id": {
"$oid": "572225d997bb651819f379f7"
},
"name": "ppg",
"projects": [
{
"name": "aaa",
"job_description": "",
"projectID": 20
},
{
"name": "bbbb",
"job_description": "",
"projectID": 21
}
]
}
I would like to update "job_description" of project with given "projectID" like this:
module.exports.saveJobDesc = function(client, idOfProject, textProvided) {
db.clients.update({ name: client},
{ $set: {'projects.0.job_description': textProvided }});
};
But instead of hardcoded index "0" of array I want to find specific project using "projectID". Is there a way to achieve this without changing the structure of collection and/or document?
If you want to update the "job_description" where name="ppg" and project_id=20 then you can use below mongo query:-
db.clients.update({ "name":"ppg","projects.projectID":20 },{$set: {"projects.$.job_description": "abcd"}})
Please let me know if any thing else is required
You cannot update multiple array elements in single update operation, instead you can update one by one which takes time depends upon number of elements in array and number of such documents in collection. see New operator to update all matching items in an array
db.test2.find().forEach( function(doc) {
var projects = doc.projects;
for(var i=0;i<projects.length;i++){
var project = projects[i];
if(project.projectID == 20){
var field = "projects."+i+".job_description";
var query = {};
query[field] = "textasdsd";
db.test2.update({ _id: doc._id},{ $set:query});
}
}
})

How can I give an empty array to Handlebars/Mustache partial?

I have a problem with partials in Handlebars.js.
This is my template and a reuseable partial for it:
Handlebars.registerPartial("children", "{{#child}}[{{age}}]{{/child}}");
var children = Handlebars.compile("{{name}} -> {{>children}}");
And here is my first data:
children({
"name": "Alice",
"child": [{
"age": 6
}, {
"age": 11
}]
});
This leads to the expected and correct output:
Alice -> [6][11]
But when I use the following data with an empty array:
children({
"name": "Bob",
"child": []
});
With this data I will get the error message:
Error: You must pass a string or Handlebars AST to Handlebars.compile. You passed function (context, options) {if (!compiled) { compiled = compileInput(); } return compiled.call(this, context, options); }
But I expected the output "Bob ->"...
When I don't use the partial doing like this, everything works fine:
var children = Handlebars.compile("{{name}} -> {{#child}}[{{age}}]{{/child}}");
But I really want to do it with the partial due to reusability. Why can't I give an empty array to this partial?
Thanks!

Categories