For my node js projects i typically have a text.json file and require it, instead of having static text within my code. something like below
JSON file
{
"greet":"Hello world"
}
var text = require('./text.json');
var greet = text.greet
I am having a little trouble in figuring out how this would work with template literals ?
I know this is an old issue but I just came up with a need for the same thing and.. yeah there are node modules that help do this but, this isn't that complex so I just made my own solution
function injectVariables( replacements, input ) {
const entries = Object.entries(replacements)
const result = entries.reduce( (output, entry) => {
const [key, value] = entry
const regex = new RegExp( `\\$\{${key}\}`, 'g')
return output.replace( regex, value )
}, input )
return result
}
const template = 'Hello my name is ${name} and I like ${language}'
const inputs = { name: 'David', language: 'JavaScript' }
const replaced = injectVariables(inputs, template)
console.log(replaced)
So, in this, it takes an input string and an object where the keys are the variable names in the string and the values are, you guessed it, the values.
It creates an array the values using Object.entries and then runs reduce across the entries to keep an updated version of the string as you go. On each iteration it makes a regex to match the variable expression and replaces that value with the one passed it.
This in particular won't look through nested objects (I didn't need that) but if for example your string had ${name.last} in it, since object keys can be strings, your input variable could be inputs = { 'name.last': 'Smith' } and it should work.
Hopefully this helps someone else.
I often use a very tiny templating helper library (tim - https://github.com/premasagar/tim) and it can be used to accomplish this:
//in my json file
var strings = {
'Hello': 'Hello {{name}}!',
'Goodbye': 'Goodbye {{name}}!'
};
//in my app
var tim = require('tim'); //templating library
var strings = require('./strings.json');
//replace
console.log(tim(strings.Hello,{name:'Fred'}));
Relevant JSFiddle:
https://jsfiddle.net/rtresjqv/
Alternatively, you could turn your strings into functions and then pass in the arguments:
//in my json file
var strings = {
'Hello': function() { return `Hello ${arguments[0]}!`; },
'Goodbye': function() { return `Goodbye {$arguments[0]}!`; }
};
//in my app
var strings = require('./strings.json');
//replace
console.log(strings.Hello('Fred'));
Fiddle:
https://jsfiddle.net/t6ta0576/
Related
How can I convert this text to JSON by nodejs?
Input :
---
title:Hello World
tags:java,C#,python
---
## Hello World
```C#
Console.WriteLine(""Hello World"");
```
Expected output :
{
title:"Hello World",
tags:["java","C#","python"],
content:"## Hello World\n```C#\nConsole.WriteLine(\"Hello World\"");\n```"
}
What I've tried to think :
use regex to get key:value array, like below:
---
{key}:{value}
---
then check if key equals tags then use string.split function by , to get tags values array else return value.
other part is content value.
but I have no idea how to implement it by nodejs.
If the input is in a known format then you should use a battle tested library to convert the input into json especially if the input is extremeley dynamic in nature, otherwise depending on how much dynamic is the input you might be able to build a parser easily.
Assuming the input is of a static structure as you posted then the following should do the work
function convertToJson(str) {
const arr = str.split('---').filter(str => str !== '')
const tagsAndTitle = arr[0]
const tagsAndTitleArr = tagsAndTitle.split('\n').filter(str => str !== '')
const titleWithTitleLabel = tagsAndTitleArr[0]
const tagsWithTagsLabel = tagsAndTitleArr[1]
const tagsWithoutTagsLabel = tagsWithTagsLabel.slice(tagsWithTagsLabel.indexOf(':') + 1)
const titleWithoutTitleLabel = titleWithTitleLabel.slice(titleWithTitleLabel.indexOf(':') + 1)
const tags = tagsWithoutTagsLabel.split(',')
const result = {
title: titleWithoutTitleLabel,
tags,
content: arr[1].slice(0, arr[1].length - 1).slice(1) // get rid of the first new line, and last new line
}
return JSON.stringify(result)
}
const x = `---
title:Hello World
tags:java,C#,python
---
## Hello World
\`\`\`C#
Console.WriteLine(""Hello World"");
\`\`\`
`
console.log(convertToJson(x))
Looks like you're trying to convert markdown to JSON. Take a look at markdown-to-json.
You can also use a markdown parser (like markdown-it) to get tokens out of the text which you'd have to parse further.
In this specific case, if your data is precisely structured like that, you can try this:
const fs = require("fs");
fs.readFile("input.txt", "utf8", function (err, data) {
if (err) {
return console.log(err);
}
const obj = {
title: "",
tags: [],
content: "",
};
const content = [];
data.split("\n").map((line) => {
if (!line.startsWith("---")) {
if (line.startsWith("title:")) {
obj.title = line.substring(6);
} else if (line.startsWith("tags")) {
obj.tags = line.substring(4).split(",");
} else {
content.push(line);
}
}
});
obj.content = content.join("\n");
fs.writeFileSync("output.json", JSON.stringify(obj));
});
Then you just wrap the whole fs.readFile in a loop to process multiple inputs.
Note that you need each input to be in a separate file and structured EXACTLY the way you mentioned in your question for this to work. For more general usage, probably try some existing npm packages like others suggest so you do not reinvent the wheel.
I have a file that contains JSON array of tasks:
currently the file contains:
[
{"task":"hey", "checked":"0", "data1":"", "data2":"", "data3":""},
{"task":"there", "checked":"0", "data1":"jiojoi", "data2":"", "data3":""}
]
I want to isolate a signle task so I use the following code:
var taskExp = new RegExp('{"task":"' + taskName + '",.*"}', '');
// Get the task
var task = taskExp.exec(text);
in this specific case, if taskName = "hey", it returns the whole string. (2 tasks).
if taskName = "there", it's ok.
Why? thanks in advance.
It's a bad idea to use regexes to filter out properties of a JSON string.
Parse it into an object (/array), then use filter, instead.
Assuming text is your JSON string:
var dataArray = JSON.parse(text),
taskName = "someTaskName";
var result = dataArray.filter(function(item){
return item.task === taskName;
});
Then, result is an array of all matching tasks.
I have some text that I receive from the user:
var text = ['Hello', 'World']; // this is the product of string.split(',')
I need to convert it into an array like this one:
var argument = [['Hello'], ['World']];
I need the input in this format so I can send multiple values to the db.
How can I do this elegantly?
I can't think of anything more elegant for this than map:
E.g.:
var argument = originalString.split(",").map(function(entry) {
return [entry];
});
Or if you've enabled ES6 on your NodeJS installation:
var argument = originalString.split(",").map((entry) => [entry]);
I'm having an issue. I want to have a static dict
var myDict={"aaa":true,"aab":false,"aac":false,"aad":true, [...] };
There are a lot of entries, and I want to have an easy access to all of them in case I need to change their value. Because of this, I don't like the single-line declaration.
As an alternative, I did manage to do the following, since multi-line text is allowed in Javascript:
var dict = {};
var loadDict = function() {
text = "aaa,true\n\
aab,false\n\
aac,false\n\
aad,true\n\[...]";
var words = text.split( "\n" );
for ( var i = 0; i < words.length; i++ ) {
var pair = words[i].split(",");
dict[ pair[0].trim() ] = pair[1].trim();
}
}
Is there a better/more elegant way of having a multi-line declaration of a dict?
note: Creating multiline strings in JavaScript is a solution only for strings. it doesn't work with a dict.
edit: I was adding a '\' at the end of each line. That was the issue. thanks.
var myDict = {
"aaa": true,
"aab": false,
"aac": false,
"aad": true,
[...]
};
I hope this is what you meant, because it's basic Javascript syntax.
Also, if for some reasons you want to "store" simple objects (made of strings, numbers, booleans, arrays or objects of the above entities) into strings, you can consider JSON:
var myDictJSON = '{\
"aaa": true,\
"aab": false,\
"aac": false,\
"aad": true,\
[...]
}';
var myDict = JSON.parse(myDictJSON);
Support for JSON is native for all the major browsers, including IE since version 8. For the others, there's this common library json2.js that does the trick.
You can also convert your simple objects into string using JSON.stringify.
that's easy-
var myDict={
"aaa":true,
"aab":false,
"aac":false,
"aad":true
};
please remember, don't place the curly bracket in the next line.
i like responses. Please respond
This (a complex data structure containing both "string" and "booleans"):
var myDict={"aaa":true,"aab":false,"aac":false,"aad":true, [...] };
Can be expressed like this:
var myDict={
"aaa":true,
"aab":false,
"aac":false,
"aad":true,
[...]
};
Similarly, this:
var myBigHairyString = "Supercalifragilsticexpialidocious";
Can be expressed like this:
var myBigHairyString =
"Super" +
"califragilstic" +
"expialidocious";
All of the MongoDB MapReduce examples I have seen have dealt with counting/adding numbers. I need to combine strings, and it looks like MapReduce is the best tool for the job. I have a large MongoDB collection in this format:
{name: userone, type: typeone}
{name: usertwo, type: typetwo}
{name: userthree, type: typeone}
Each name only has one type, but names are not necessarily unique. I want to end up with a collection that lists all names for a particular type, either in a comma separated list or an array, like this:
{type: typeone, names: userone, usertwo}
{type: typetwo, names: userthree}
I was trying to use MapReduce to accomplish this. My function works correctly when there is only one user for a type. However, when there is more than one user, 'undefined' is stored in the names field.
I'm not very good at Javascript, and I'm still learning MongoDB so it's probably a simple data type or scope error.
Here are my map and reduce functions. What's wrong with them?
map = function() {
emit(this.user,{type:this.type});
}
reduce = function(key, values) {
var all="";
for(var i in values) {
all+=values[i]['type']+",";
}
return all;
}
It looks to me like you're trying to do a group-by via type. If so, you should be emitting type first. From there, its pretty much the same as your code, but I took the liberty of cleaning it up a bit.
Beware, the reduce function could get called multiple times on smaller groups. Therefore, if you used your code in a sharded environment, you may get extra trailing commas. See Reduce Function for more information.
Map:
m = function(){ emit(this.type, {names:this.name}); }
Reduce:
r = function(key, values){
var all = [];
values.forEach(function(x){
all.push(x.names)
})
return {"names": all.join(", ")};
}
Usage:
res = db.users.mapReduce(m,r); db[res.result].find()
Alternate:
Per OP request, here is a version that returns an array for names instead of a comma separated list string:
m = function () {
emit(this.type, {names:this.name});
}
r = function (key, values) {
var all = [];
values.forEach(function (x) {all.push(x.names);});
return {type:key, names:all};
}
f = function (w, r) {
r.names = r.names[0];
return r
}
res = db.users.mapReduce(m,r, {finalize:f}); db[res.result].find()
Cheers!