MongoDB: How to call a function defined in another JS file? - javascript

I have a function defined called func1 in file file_a.js
I have another file file_b.js, in which I want to use the function func1.
Can I do this inside mongo environment?

Amended answer thanks to AD7six
Mongodb console can take multiple input file loaded in order specified.
Or you can use the built in load function like this
➜ mongotest cat test.js
load("test2.js");
print("test.js");
foo();
➜ mongotest cat test2.js
var foo = function() {
print("test2.js");
};
➜ mongotest mongo test.js
MongoDB shell version: 2.0.6
connecting to: test
test.js
test2.js
test.js is the file given to mongodb console, it loads test2.js(containing function foo) and calls foo

If you are meaning via the cli (are you?), you can load multiple js files via the mongo shell
$ mongo --help
MongoDB shell version: 2.0.6
usage: mongo [options] [db address] [file names (ending in .js)]
Note file name s
Therefore, you can just load both files, and the contents of file_a will be available to file_b:
mongo [args] dbname file_a.js file_b.js

Related

JS, Browserify: function not defined

I have files as represented:
-js/
- calc.js
- tool.js
-index.html
calc.js is a node module of following structure:
module.exports = {
calculate: function() {...},
getPrecision: function() {...}
}
and tool.js use require and adds some functions, like that:
const fpcalc = require('./fpcalc');
function changeState() {
//some code using fpcalc
}
I used Browserify to generate bundle.js and added that as script src.
One of my buttons on HTML page is using onclick=changeState(). After clicking I'm getting
ReferenceError: changeState is not defined
at HTMLAnchorElement.onclick
Why is that? Is there any other way to make it work?
The function "changeState" is not exported in your tool.js.
That means it is only visible inside your bundle.js, but not outside.
Have a look at this: https://makerlog.org/posts/creating-js-library-builds-with-browserify-and-other-npm-modules
It shows you how to expose your code to the global namespace in javascript.
Here's a very simple way to make it work like you want.
const fpcalc = require('./fpcalc');
window.changeState = () => {
//some code using fpcalc
}
I have same error, here is my working example.
mac, browserify https://github.com/perliedman/reproject
Must use sudo install globally
sudo npm install -g brwoserify
https://github.com/perliedman/reproject
sudo npm install reproject // install locally is fine
Must manually create 'dist' folder for later output file use
Must use --s expose global variable function 'reproject' and or 'toWgs84' you will use later in browser js.
Without --s , will get 'reproject' undefined error . https://makerlog.org/posts/creating-js-library-builds-with-browserify-and-other-npm-modules
browserify --help will list all options.
-o means output file directory
browserify node_modules/reproject/index.js --s reproject -o node_modules/reproject/dist/reproject.js
HTML script tag include your above dist/reproject.js
Now, you will not get 'reproejct' undefined error
return reproject(_geometry_, ___from_projection, proj4.WGS84, crss)

NodeJS module executing user script with external function not found

I am quite new to nodeJS.
I am using the nodeJS module node-workflow
Basically, this module is an orchestrator that takes a custom javascript script (=workflow definition), then serialize it and store it in a REDIS db (for example), and execute on-demand later on by the node-workflow module.
A workflow definition is composed of task, like this:
var my_external_module = require('my_external_module');
var workflow = module.exports = {
name: 'Workflow Test',
chain: [{
name: 'TASK 1',
timeout: 30,
retry: 1,
body: function(job, cb) {
// Execute external function
my_external_module.hello("Monkey");
return cb(null)
},
},
...
First I put my function my_external_module.hello() in a .js file beside the workflow script.
When I run the node-workflow module I get the following error:
Error initializing runner:
[ReferenceError: my_external_module is not defined]
So I have created a module my_external_module,
and in: ./node_modules/my_external_module/index.js
module.exports = {
hello: function(name) {
console.log("Hello, " + name);
}
};
When I run the node-workflow module I get the same error:
Error initializing runner:
[ReferenceError: my_external_module is not defined]
It seems that the require(...) shall stands in one of the .js files of the node-workflow module, so I would have to hack one of the files of the module, but it is a bit dirty.
Is there something I missed?
Or is there a way to define a $PATH like in Python in order to my function to be accessible from everywhere.
You have to require it as:
var my_external_module = require('./my_external_module');
Notice the ./ this means Node should search for a file like ./my_external_module.js
If you omit the ./ Node looks at the installed modules on (usually) node_modules directory

Run function in script from command line (Node JS)

I'm writing a web app in Node. If I've got some JS file db.js with a function init in it how could I call that function from the command line?
No comment on why you want to do this, or what might be a more standard practice: here is a solution to your question.... Keep in mind that the type of quotes required by your command line may vary.
In your db.js, export the init function. There are many ways, but for example:
module.exports.init = function () {
console.log('hi');
};
Then call it like this, assuming your db.js is in the same directory as your command prompt:
node -e 'require("./db").init()'
If your db.js were a module db.mjs, use a dynamic import to load the module:
node -e 'import("./db.mjs").then( loadedModule => loadedModule.init() )'
To other readers, the OP's init function could have been called anything, it is not important, it is just the specific name used in the question.
Update 2020 - CLI
As #mix3d pointed out you can just run a command where file.js is your file and someFunction is your function optionally followed by parameters separated with spaces
npx run-func file.js someFunction "just some parameter"
That's it.
file.js called in the example above
const someFunction = (param) => console.log('Welcome, your param is', param)
// exporting is crucial
module.exports = { someFunction }
More detailed description
Run directly from CLI (global)
Install
npm i -g run-func
Usage i.e. run function "init", it must be exported, see the bottom
run-func db.js init
or
Run from package.json script (local)
Install
npm i -S run-func
Setup
"scripts": {
"init": "run-func db.js init"
}
Usage
npm run init
Params
Any following arguments will be passed as function parameters init(param1, param2)
run-func db.js init param1 param2
Important
the function (in this example init) must be exported in the file containing it
module.exports = { init };
or ES6 export
export { init };
As per the other answers, add the following to someFile.js
module.exports.someFunction = function () {
console.log('hi');
};
You can then add the following to package.json
"scripts": {
"myScript": "node -e 'require(\"./someFile\").someFunction()'"
}
From the terminal, you can then call
npm run myScript
I find this a much easier way to remember the commands and use them
Try make-runnable.
In db.js, add require('make-runnable'); to the end.
Now you can do:
node db.js init
Any further args would get passed to the init method, in the form of a list or key-value pairs.
Sometimes you want to run a function via CLI, sometimes you want to require it from another module. Here's how to do both.
// file to run
const runMe = () => {}
if (require.main === module) {
runMe()
}
module.exports = runMe
This one is dirty but works :)
I will be calling main() function from my script. Previously I just put calls to main at the end of script. However I did add some other functions and exported them from script (to use functions in some other parts of code) - but I dont want to execute main() function every time I import other functions in other scripts.
So I did this,
in my script i removed call to main(), and instead at the end of script I put this check:
if (process.argv.includes('main')) {
main();
}
So when I want to call that function in CLI: node src/myScript.js main
simple way:
let's say you have db.js file in a helpers directory in project structure.
now go inside helpers directory and go to node console
helpers $ node
2) require db.js file
> var db = require("./db")
3) call your function (in your case its init())
> db.init()
hope this helps
Updated for 2022 - If you've switched to ES Modules, you can't use the require tricks, you'd need to use dynamic imports:
node -e 'import("./db.js").then(dbMod => dbMod.init());'
or with the --experimental-specifier-resolution=node flag:
node --experimental-specifier-resolution=node -e 'import("./db").then(dbMod => dbMod.init());'
If you turn db.js into a module you can require it from db_init.js and just: node db_init.js.
db.js:
module.exports = {
method1: function () { ... },
method2: function () { ... }
}
db_init.js:
var db = require('./db');
db.method1();
db.method2();
I do a IIFE, something like that:
(() => init())();
this code will be executed immediately and invoke the init function.
You can also run TypeScript with ts-node similar to #LeeGoddard answer.
In my case, I wanted to use app and init separately for testing purposes.
// app.ts
export const app = express();
export async function init(): Promise<void> {
// app init logic...
}
npx ts-node -e 'require("./src/app").init();'
npx ts-node -e 'import("./src/app").then(a => a.init());' // esmodule
maybe this method is not what you mean, but who knows it can help
index.js
const arg = process.argv.splice(2);
function printToCli(text){
console.log(text)
}
switch(arg[0]){
case "--run":
printToCli("how are you")
break;
default: console.log("use --run flag");
}
and run command node . --run
command line
probuss-MacBook-Air:fb_v8 probus$ node . --run
how are you
probuss-MacBook-Air:fb_v8 probus$
and you can add more arg[0] , arg[1], arg[2] ... and more
for node . --run -myarg1 -myarg2
If you want to include environment variables from your .env files, you can use env-cmd:
npx env-cmd node -e 'require("./db").init()'
If you want run a specific function in the file too, use run-func:
npx env-cmd npx run-func db.js init someArg
Or, to provide an argument for the accepted answer you'd have to do something like:
npx env-cmd node -e 'require("./db").init(someArg)'
Writing/updating an expression here is less explicit (so easier to miss when you're checking back, for example) than providing different arguments to the commands, so I recommend using env-cmd with run-func.
Note: I also usually add --experimental-modules on the end when necessary.
Inspired by https://github.com/DVLP/run-func/blob/master/index.js
I create https://github.com/JiangWeixian/esrua
if file index.ts
export const welcome = (msg: string) => {
console.log(`hello ${msg}`)
}
just run
esrua ./index.ts welcome -p world
will output hello world
If your file just contains your function, for example:
myFile.js:
function myMethod(someVariable) {
console.log(someVariable)
}
Calling it from the command line like this nothing will happen:
node myFile.js
But if you change your file:
myFile.js:
myMethod("Hello World");
function myMethod(someVariable) {
console.log(someVariable)
}
Now this will work from the command line:
node myFile.js

How to pass argument to Mongo Script

I've been using mongo and script files like this:
$ mongo getSimilar.js
I would like to pass an argument to the file:
$ mongo getSimilar.js apples
And then in the script file pick up the argument passed in.
var arg = $1;
print(arg);
Use --eval and use shell scripting to modify the command passed in.
mongo --eval "print('apples');"
Or make global variables (credit to Tad Marshall):
$ cat addthem.js
printjson( param1 + param2 );
$ ./mongo --nodb --quiet --eval "var param1=7, param2=8" addthem.js
15
You can't do that, but you could put them in another script and load that first:
// vars.js
msg = "apples";
and getSimilar.js was:
print(msg);
Then:
$ mongo vars.js getSimilar.js
MongoDB shell version: blah
connecting to: test
loading file: vars.js
loading file: getSimilar.js
apples
Not quite as convenient, though.
Set a shell var:
password='bladiebla'
Create js script:
cat <<EOT > mongo-create-user.js
print('drop user admin');
db.dropUser('admin');
db.createUser({
user: 'admin',
pwd: '${password}',
roles: [ 'readWrite']
});
EOT
Pass script to mongo:
mongo mongo-create-user.js
I used a shell script to pipe a mongo command to mongo. In the mongo command I used an arg I passed to the shell script (i.e. i used $1):
#!/bin/sh
objId=$1
EVAL="db.account.find({\"_id\" : \"$objId\"})"
echo $EVAL | mongo localhost:27718/balance_mgmt --quiet
2022 update:
when using mongosh you can read the execution arguments from process.argv
mongosh script.js param1 param2
// process.argv will be [.... , 'param1', param2']
the tricky bit is that mongosh will try to execute the parameters (e.g. param1 and param2) as additional scripts, but this can be prevented by ending the script using quit(). (TBH, I'm not sure it's by design / intended / documented)
I wrote a small utility to solve the problem for myself. With the mongoexec utility, you would be able to run the command ./getSimilar.js apples by adding the following to the beginning of your script:
#!/usr/bin/mongoexec --quiet
Within the script, you can then access the arguments as args[0].
https://github.com/pveierland/mongoexec
I solved this problem, by using the javascript bundler parcel: https://parceljs.org/
With this, one can use node environment variables in a script like:
var collection = process.env.COLLECTION;
when building with parcel, the env var gets inlined:
parcel build ./src/index.js --no-source-maps
The only downside is, that you have to rebuild the script every time you want to change the env vars. But since parcel is really fast, this is not really a problem imho.

How do I load my script into the node.js REPL?

I have a script foo.js that contains some functions I want to play with in the REPL.
Is there a way to have node execute my script and then jump into a REPL with all the declared globals, like I can with python -i foo.py or ghci foo.hs?
There is still nothing built-in to provide the exact functionality you describe. However, an alternative to using require it to use the .load command within the REPL, like such:
.load foo.js
It loads the file in line by line just as if you had typed it in the REPL. Unlike require this pollutes the REPL history with the commands you loaded. However, it has the advantage of being repeatable because it is not cached like require.
Which is better for you will depend on your use case.
Edit: It has limited applicability because it does not work in strict mode, but three years later I have learned that if your script does not have 'use strict', you can use eval to load your script without polluting the REPL history:
var fs = require('fs');
eval(fs.readFileSync('foo.js').toString())
i always use this command
node -i -e "$(< yourScript.js)"
works exactly as in Python without any packages.
I made Vorpal.js, which handles this problem by turning your node add into an interactive CLI. It supports a REPL extension, which drops you into a REPL within the context of your running app.
var vorpal = require('vorpal')();
var repl = require('vorpal-repl');
vorpal
.delimiter('myapp>')
.use(repl)
.show()
.parse(process.argv);
Then you can run the app and it will drop into a REPL.
$ node myapp.js repl
myapp> repl:
Another way is to define those functions as global.
global.helloWorld = function() { console.log("Hello World"); }
Then preload the file in the REPL as:
node -r ./file.js
Then the function helloWorld can be accessed directly in the REPL.
Here's a bash function version of
George's answer:
noderepl() {
FILE_CONTENTS="$(< $1 )"
node -i -e "$FILE_CONTENTS"
}
If you put this in your ~/.bash_profile you can use it like an alias, i.e.:
noderepl foo.js
I created replpad since I got tired of reloading the script repeatedly.
Simply install it via: npm install -g replpad
Then use it by running: replpad
If you want it to watch all files in the current and all subdirectories and pipe them into the repl when they change do: replpad .
Check out the videos on the site to get a better idea of how it works and learn about some other nice features that it has like these:
access core module docs in the repl via the dox() function that is added to every core function, i.e. fs.readdir.dox()
access user module readmes in the repl via the dox() function that is added to every module installed via npm,
i.e. marked.dox()
access function's highlighted source code, info on where function was defined (file, linenumber) and function
comments and/or jsdocs where possible via the src property that is added to every function, i.e. express.logger.src
scriptie-talkie support (see .talk command)
adds commands and keyboard shortcuts
vim key bindings
key map support
parens matching via match token plugin
appends code entered in repl back to file via keyboard shortcut or .append command
See: https://github.com/thlorenz/replpad
Why not load the file into an interactive node repl?
node -h
-e, --eval script evaluate script
-i, --interactive always enter the REPL even if stdin
node -e 'var client = require("./build/main/index.js"); console.log("Use `client` in repl")' -i
Then you can add to package.json scripts
"repl": "node -e 'var client = require(\"./build/main/index.js\"); console.log(\"Use `client` in repl\")' -i",
tested using node v8.1.2
Currently you can't do that directly, but you can mylib = require('./foo.js') in the REPL. Remember methods are exported, not declared as globals.
replpad is cool, but for a quick and easy way to load a file into node, import its variables and start a repl, you can add the following code to the end of your .js file
if (require.main === module){
(function() {
var _context = require('repl').start({prompt: '$> '}).context;
var scope = require('lexical-scope')(require('fs').readFileSync(__filename));
for (var name in scope.locals[''] )
_context[scope.locals[''][name]] = eval(scope.locals[''][name]);
for (name in scope.globals.exported)
_context[scope.globals.exported[name]] = eval(scope.globals.exported[name]);
})();
}
Now if your file is src.js, running node src.js will start node, load the file, start a REPL, and copy all the objects declared as var at the top level as well as any exported globals.
The if (require.main === module) ensures that this code will not be executed if src.js is included through a require statement. I fact, you can add any code you want to be excuted when you are running src.js standalone for debugging purposes inside the if statement.
Another suggestion that I do not see here: try this little bit of code
#!/usr/bin/env node
'use strict';
const repl = require('repl');
const cli = repl.start({ replMode: repl.REPL_MODE_STRICT });
cli.context.foo = require('./foo'); // injects it into the repl
Then you can simply run this script and it will include foo as a variable
Old answer
type test.js|node -i
Will open the node REPL and type in all lines from test.js into REPL, but for some reason node will quit after file ends
Another problem is, that functions will not be hoisted.
Better answer
node -e require('repl').start({useGlobal:true}); -r ./test2.js
Then all globals declared without var within test2.js will be available in the REPL
not sure why var a in global scope will not be available
There is an Official Node.js REPL that supports also async methods
console.js
const repl = require('repl')
const mongoose = require('mongoose')
const run = async () => {
await mongoose.connect(process.env.DB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const r = repl.start(`(${process.env.NODE_EN}) ⚡️ `)
r.context.User = require('./src/models/user.model')
r.context.mongoose = mongoose
console.log(`Ready 🚀`);
}
run()
Start the console:
NODE_OPTIONS=--experimental-repl-await node console.js
User model its exposed to console
await User.find({})
source

Categories

Resources