I am learning nodejs , I find two way to exports our function in Nodejs , but I can not find what is difference between in those
The first is
module.exports.UserService = (function () {
return {
getUser:getUser
}
})()
And another
var getUser=function(searchInfo,res){}
module.exports.getUser=getUser
Is there any disadvantage or advantage of using , or any other best practice for exports function
I always find it better to use the first notation (exporting the object via its reference) because:
it allows you to build the object incrementally, and
allows you to reference the object within itself.
e.g.:
var Obj = {};
Obj.attrs = { "prop1": "val1", "prop2": "val2" };
addSomeProperties(Obj); /* possibly based on Obj.attrs */
module.exports = Obj;
Related
I have
// file cars.js
var bodyshop = require('./bodyshop')
var connections = [];
many functions which operate on connections. adding them, changing them etc.
code in this file includes things like
bodyshop.meld(blah)
bodyshop.mix(blah)
exports.connections = connections
and then
// file bodyshop.js
let cars = require('./cars');
even more functions which operate on connections. adding them, changing them etc.
code in this file includes things like
cars.connections[3].color = pink
cars.connections.splice(deleteMe, 1)
module.exports = { meld, mix, flatten }
Is it absolutely honestly the case that code in bodyshop such as cars.connections.splice(deleteMe, 1) will indeed delete an item from "the" connections (ie, the one and only connections, declared in cars.js) and code in bodyshop such as cars.connections[3].color = pink will indeed change the color of index 3 of "the" self-same one and only connections?
Is it quite OK / safe / acceptable that I used the syntax "module.exports = { }" at the end of bodyshop, rather than three lines like "exports.meld = meld" ?
Is this sentence indeed to totally correct?? "In Node.js if you export from M an array, when using the array in another module X which requires M, the array will be by reference in X, i.e. not by copy" ... ?
I created two files with the following methods and the array as you mentioned.
First File: test1.js
const testArray = [];
const getArray = () => {
return testArray;
};
module.exports = {
testArray,
getArray
}
Second File: test2.js
const { testArray, getArray } = require('./test1');
console.log('testing the required array before modifying it');
console.log(getArray());
testArray.push('test');
console.log('testing the method result after modifying the required array content');
console.log(getArray());
If you can create the mentioned files and run them locally, you will see the following result.
>node test2.js
testing the required array before modifying it
[]
testing the method result after modifying the required array content
[ 'test' ]
The points observed is,
yes, it's okay if you want to export it with the syntax module.exports = { }, It not much an issue.
If any of the methods modify this array outside of the required file, it will affect here as well, This because require will be a reference, not a copy.
The one possible solution will be creating a JSON copy of it while requiring as below:
const { testArray, getArray } = require('./test1');
const testArrayCopy = JSON.parse(JSON.stringify(testArray));
console.log('testing the required array before modifying it');
console.log(getArray());
testArrayCopy.push('test');
console.log('testing the method result after modifying the required array content');
console.log(getArray());
This is the result:
>node test2.js
testing the required array before modifying it
[]
testing the method result after modifying the required array content
[]
Note: JSON copy will not help you in parsing DateTime properly.
I'm trying to select certain keys from an JSON array, and filter the rest.
var json = JSON.stringify(body);
which is:
{
"FirstName":"foo",
"typeform_form_submits":{
"foo":true,
"bar":true,
"baz":true
},
"more keys": "foo",
"unwanted key": "foo"
}
Want I want:
{
"FirstName":"foo",
"typeform_form_submits":{
"foo":true,
"bar":true,
"baz":true
}
}
I've checked out How to filter JSON data in node.js?, but I'm looking to do this without any packages.
Now you can use Object.fromEntries like so:
Object.fromEntries(Object.entries(raw).filter(([key]) => wantedKeys.includes(key)))
You need to filter your obj before passing it to json stringify:
const rawJson = {
"FirstName":"foo",
"typeform_form_submits":{
"foo":true,
"bar":true,
"baz":true
},
"more keys": "foo",
"unwanted key": "foo"
};
// This array will serve as a whitelist to select keys you want to keep in rawJson
const filterArray = [
"FirstName",
"typeform_form_submits",
];
// this function filters source keys (one level deep) according to whitelist
function filterObj(source, whiteList) {
const res = {};
// iterate over each keys of source
Object.keys(source).forEach((key) => {
// if whiteList contains the current key, add this key to res
if (whiteList.indexOf(key) !== -1) {
res[key] = source[key];
}
});
return res;
}
// outputs the desired result
console.log(JSON.stringify(filterObj(rawJson, filterArray)));
var raw = {
"FirstName":"foo",
"typeform_form_submits":{
"foo":true,
"bar":true,
"baz":true
},
"more keys": "foo",
"unwanted key": "foo"
}
var wantedKeys =["FirstName","typeform_form_submits" ]
var opObj = {}
Object.keys(raw).forEach( key => {
if(wantedKeys.includes(key)){
opObj[key] = raw[key]
}
})
console.log(JSON.stringify(opObj))
I know this question was asked aways back, but I wanted to just toss out there, since nobody else did:
If you're bound and determined to do this with stringify, one of its less-well-known capabilities involves replacer, it's second parameter. For example:
// Creating a demo data set
let dataToReduce = {a:1, b:2, c:3, d:4, e:5};
console.log('Demo data:', dataToReduce);
// Providing an array to reduce the results down to only those specified.
let reducedData = JSON.stringify(dataToReduce, ['a','c','e']);
console.log('Using [reducer] as an array of IDs:', reducedData);
// Running a function against the key/value pairs to reduce the results down to those desired.
let processedData = JSON.stringify(dataToReduce, (key, value) => (value%2 === 0) ? undefined: value);
console.log('Using [reducer] as an operation on the values:', processedData);
// And, of course, restoring them back to their original object format:
console.log('Restoration of the results:', '\nreducedData:', JSON.parse(reducedData), '\nprocessedData:', JSON.parse(processedData));
In the above code snippet, the key value pairs are filtered using stringify exclusively:
In the first case, by providing an array of strings, representing the keys you wish to preserve (as you were requesting)
In the second, by running a function against the values, and dynamically determining those to keep (which you didn't request, but is part of the same property, and may help someone else)
In the third, their respective conversions back to JSON (using .parse()).
Now, I want to stress that I'm not advocating this as the appropriate method to reduce an object (though it will make a clean SHALLOW copy of said object, and is actually surprisingly performant), if only from an obscurity/readability standpoint, but it IS a totally-effective (and mainstream; that is: it's built into the language, not a hack) option/tool to add to the arsenal.
everyone!
I am reading some code in an attempt to learn node.js, it's available here.
Anyways, I have a few questions regarding some of the syntax of JS. The first bits are in index.html
1.
var argv = require("minimist")(process.argv.slice(2), {
default: { albums: true }
});
What is going on after the comma? Are we setting default values? We never declared albums, so then how are we setting a default value?
2.
What do we call it when we have a module, then a statement in parenthesis? Is this part of overriding the constructor?
var sinceDate = require("moment")(argv.sinceDate, "YYYY/MM/DD");
var sinceDate = require("moment")(argv.sinceDate, "YYYY/MM/DD");
if (!sinceDate.isValid()) {
require("debug")("download")(
"invalid sinceDate '" +
argv.sinceDate +
"', date filter disabled (get all)."
);
sinceDate = 0;
}
In get_all.js , it is used in the third line.
var debug = require("debug")("json");
Thanks a bunch!
To understand this you need to first understand in JavaScript function are First-Class Functions, mean functions can be treated as regular variables. Thus you can pass those as arguments to other functions aka callbacks, or you can return a function from a function aka Closure. Also you can store functions into another variables.
For more: https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function
Answers to your questions:
1.
var argv = require("minimist")(process.argv.slice(2), {
default: { albums: true }
});
What is going on after the comma? Are we setting default values? We never declared albums, so then how are we setting a default value?
Answer:
Yes we are setting default values, but not for the variables you declared rather you are passing these default values to "minimist" module. This module is probably using albums and what you asked it that the default value for albums is true.
2.
What do we call it when we have a module, then a statement in parenthesis? Is this part of overriding the constructor?
var sinceDate = require("moment")(argv.sinceDate, "YYYY/MM/DD");
var sinceDate = require("moment")(argv.sinceDate, "YYYY/MM/DD");
if (!sinceDate.isValid()) {
require("debug")("download")(
"invalid sinceDate '" +
argv.sinceDate +
"', date filter disabled (get all)."
);
sinceDate = 0;
}
In get_all.js , it is used in the third line.
var debug = require("debug")("json");
Answer:
As we discussed above functions being First-Class Functions. Here the "moment" module is returning a constructor function and you are calling that constructor function just after requiring it. Though it can be done as follow:
var moment = require("moment");
var sinceDate = moment(argv.sinceDate, "YYYY/MM/DD");
In above code, I required moment library once and used it as constructor function for sinceDate.
The same concept is for module debug, its returning a function and you are calling that function just after require with argument json.
I've traded node-DBI for knex because it has more function that I require.
So far I'd make the same choice again but only one thing is holding me back: writing abstract methods that take a options variable where params like where, innerjoin and such are contained in.
Using node-dbi I could easily forge a string using these variables but I can't seem to create the knex chain dymanicly because after using a switch, you'd get knex.method is not a function.
Any idea how to resolve this?
I'm looking for something as in
`getData(table,options){
var knex=knex
if(options.select)
/** append the select data using knex.select()
if(options.where)
/** append the where data using knex.where(data)*/
if(options.innerJoin)
/** append innerjoin data*/
}`
This way I can avoid having to write alot of DB functions and let my Business Logical Layers handel the requests
/*This function serves as the core of our DB layer
This will generate a SQL query and execute it whilest returning the response prematurely
#param obj:{Object} this is the options object that contain all of the query options
#return Promise{Object}: returns a promise that will be reject or resolved based on the outcome of the query
The reasoning behind this kind of logic is that we want to abstract our layer as much as possible, if evne the slightest
sytnax change occurs in the near future, we can easily update all our code by updating this one
We are using knex as a query builder and are thus relying on Knex to communicate with our DB*/
/*Can also be used to build custom query functions from a data.service. This way our database service will remain
unpolluted from many different functions and logic will be contained in a BLL*/
/* All available options
var options = {
table:'table',
where:{operand:'=',value:'value',valueToEqual:'val2'},
andWhere:[{operand:'=',value:'value',valueToEqual:'val2'}],
orWhere:[{operand:'=',value:'value',valueToEqual:'val2'}],
select:{value:['*']},
insert:{data:{}},
innerJoin:[{table:'tableName',value:'value',valueToEqual:'val2'}],
update:{data:{}}
}*/
/*Test object*/
/*var testobj = {
table:'advantage',
where:{operand:'>',value:'id',valueToEqual:'3'},
select:{value:['*']},
innerJoin:{table:'User_Advantage',value:'User_Advantage.Advantageid',valueToEqual:'id'}
}
var testobj = {
table:'advantage',
where:{operand:'>',value:'id',valueToEqual:'3'},
select:{value:['*']},
innerJoin:{table:'User_Advantage',value:'User_Advantage.Advantageid',valueToEqual:'id'}
}
queryBuilder(testobj)*/
function queryBuilder(options){
var promise = new Promise(function (resolve, reject) {
var query;
for (var prop in options) {
/*logger.info(prop)*/
if (options.hasOwnProperty(prop)) {
switch (prop) {
case 'table':
query = knex(options[prop]);
break;
case 'where':
query[prop](options[prop].value, options[prop].operand, options[prop].valueToEqual);
break;
/*andWhere and orWhere share the same syntax*/
case 'andWhere':
case 'orWhere':
for(let i=0, len=options[prop].length;i<len;i++){
query[prop](options[prop][i].value, options[prop][i].operand, options[prop][i].valueToEqual);
}
break;
case 'select':
query[prop](options[prop].value);
break;
/*Same syntax for update and insert -- switch fallthrough*/
case 'insert':
case 'update':
query[prop](options[prop].data);
break;
case 'innerJoin':
for(let i=0, len=options[prop].length;i<len;i++){
query[prop](options[prop][i].table, options[prop][i].value, options[prop][i].valueToEqual);
}
break;
}
}
}
return query
.then(function (res) {
return resolve(res);
}, function (error) {
logger.error(error)
return reject(error);
})
return reject('Options wrongly formatted');
});
return promise
}
Thanks to Molda I was able to produce the code above. This one takes a Object called options in as a parameter and will build the knex chain based on this value. See the comments for the syntax of Object
Not every knex query option has been included but this will serve as a good base for anyone trying to achieve a similar effect.
Some examples to use this:
/*Will return all values from a certain table
#param: table{String}: string of the table to query
#param: select{Array[String]}: Array of strings of columns to be select -- defaults to ['*'] */
function getAll(table,select) {
/*Select * from table as default*/
var selectVal=select||['*']
var options={
table:table,
select:{value:selectVal}
}
return queryBuilder(options)
}
or a more specific use case:
function getUserAdvantages(userid){
var options = {
table:'advantage',
innerJoin:[{table:TABLE,value:'advantage.id',valueToEqual:'user_advantage.Advantageid'}],
where:{operand:'=',value:'user_advantage.Userid',valueToEqual:userid}
}
return sqlService.queryBuilder(options)
}
Note: the sqlService is a module of node that I export containing the queryBUilder method.
Edit: I wanted to add that the only roadblock I had was using the .from / .insert from Knex. I no longer use these methods as they resulted in errors when using them. Ive used knex(table) as commented.
I need a dynamic variable in nodejs .
I use the allocine-api, and she return, a different object when I use it . For example :
allocine.api(type, {code: code}, function(error, result) {
if(error){
console.log('Error : '+ error);
return;
}
socket.emit("allocine_"+type ,result);
});
if type is "movie", result contain a movie object, but if type is "tvseries", result contain a tvseries object. So I need to take the variable "originalTitle" in "tvseries" or "movie" object, so I need to make this :
result.<type>.originalTitle
But, how to use the contain of "type" for this ?
I have try with the javascript method, and the use of "window['type']", but it's don't work in nodeJs .
as javascript objects elements can be accessed as an associative array ( cf mozilla js doc )
using myobject.myproperties is strictly equal to use myobject["myproperties"]
so if a var hold the properties name to read var myvar = "myproperties"; you could also use myobject[myvar]
so, concretely :
var o = {
tvseries : {
originalTitle : "hello world"
}
}, type = "tvseries";
console.log( o[type].originalTitle );
jsfiddle
also, if the result object get only one sub object, named by the type, you can get type name directly from it
var type = Object.keys( myobject )[0];
jsfiddle
or more simply :
var theTitle = myobject[ Object.keys( myobject )[0] ].originalTitle;
jsfiddle
var results = {};
results.a = {originalTitle: "One"};
var results2 = {b:{originalTitle: "Two"}};
console.log(results['a'].originalTitle); //now one
console.log(results2['b'].originalTitle); //now Two
With two ways of creating the object.
Try the fiddle:
http://jsfiddle.net/rmoskal/6rf0juq6/