Executing mongodb scripts via mongoid Rails - javascript

I have a mongo db script in a js file:
query.js
//conn = new Mongo();
//db = conn.getDB("dbName");
functionFoo = function (arg){
//----process arg
}
also I have an array of args known as args_array, (that I fetch from database using mongoid) for which I want to do something like this:
args_array.each do |arg|
//some how call functionFoo(arg) from the query.js file
end
is this possible in rails?
I am able to execute the file from terminal but I want to wrap it in my application so that I can use it from rails console.

I know this old question but in case you still need answer or any one else. This answer works with gem mongo ~> 2.3.
The key to answer you do not need mongoid in this case - in my case I use it for rails model, so I use mongoid (5.1.0) only to get DB connection db = Mongoid.default_client.database - or you can get/create database using mongo gem.
To execute javascript on database you need to call command method db.command({ eval: 'js' }) or db.command({ eval: 'function(n){return db.projects.find({name: n}).toArray();}', args: ['beskhai'], nolock: true })
To get the result you can call .documents db.command(...).documents, The return is a hash {retval: it will be return of you script, ok: is 1 if success} the return object of command call is [Mongo::Operation::Result] https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/operation/result.rb.

I'm using MongoID 6.0.1, and it easy to query everything you want like that:
db ||= Mongoid.default_client.database
f = """
functionFoo = function (arg){
//----process arg
}
"""
result = db.command({:$eval => f, args: [arg1, arg2, ...arg_n], nolock: true})
#result_data = result.first['retval']
It not only a function, just every thing you want to do with command.
My example is:
db ||= Mongoid.default_client.database
f = """
var collectionNames = db.getCollectionNames(), stats = [];
collectionNames.forEach(function (n) { stats.push(db[n].stats()); });
stats = stats.sort(function(a, b) { return b['size'] - a['size']; });
return stats;
"""
result = db.command({:$eval => f, args: [], nolock: true})
#result_data = result.first['retval']

Related

How to know what parameters are available in a callback function? Javascript, MongoDB

I am a beginner in JavaScript and web development in general. I've been studying by myself and have hit numerous roadblocks along the way.
Right now, I am very confused about functions with callback functions and its parameters. I have read documentations about these but they are currently too high level for me. I just have a few questions based on the two code snippets below.
How do I know what parameters are available in the callback functions? In #1, #2 and #3, they have different second parameters and in #4 it has no second parameter.
Is err argument always in the first parameter when you have more than 1 parameters? Can I choose not not have an err parameter? Can I choose so that err is not the first parameter?
How do I know if a function can have a callback function?
Lastly, I do not understand why in #99.1, callback(result) has an argument of result when the callback function in #99.2 is just function() { client.close() }? Why not just callback()?
Advanced thank you to anyone who will provide an idea about this! Thank you! Any reference, guide or tutorials would be a huge help.
Here are the code sources.
First code snippet source (Insert a Document)
Second code snippet source (collection example)
const MongoClient = require('mongodb').MongoClient;
const test = require('assert');
// Connection url
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'test';
// Connect using MongoClient
MongoClient.connect(url, function(err, client) { <-------------------- #1
// Create a collection we want to drop later
const col = client.db(dbName).collection('createIndexExample1');
// Show that duplicate records got dropped
col.find({}).toArray(function(err, items) { <-------------------- #2
expect(err).to.not.exist;
test.equal(4, items.length);
client.close();
});
});
const insertDocuments = function(db, callback) {
// Get the documents collection
const collection = db.collection('documents');
// Insert some documents
collection.insertMany([
{a : 1}, {a : 2}, {a : 3}
], function(err, result) { <---------------------- #3
assert.equal(err, null);
assert.equal(3, result.result.n);
assert.equal(3, result.ops.length);
console.log("Inserted 3 documents into the collection");
callback(result); <----------------------- #99.1
});
}
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'myproject';
const client = new MongoClient(url, {useNewUrlParser: true});
// Use connect method to connect to the server
client.connect(function(err) { <---------------------- #4
assert.equal(null, err);
console.log("Connected successfully to server");
const db = client.db(dbName);
insertDocuments(db, function() { <------------------------ #99.2
client.close();
});
});
The best option is usually to consult the documentation.
The MongoClient.connect() doc (both #1 and #4) takes a callback function of type Callback<MongoClient>:
connect(callback: Callback<MongoClient>): void
And the Callback documentation is:
Callback<T>: (error?: AnyError, result?: T) => void
Defined in src/utils.ts:36
Type parameters
T = any
Type declaration
(error?: AnyError, result?: T): void
MongoDB Driver style callback
Parameters
Optional error: AnyError
Optional result: T
Returns void
Similarly toArray:
toArray(callback: Callback<TSchema[]>): void
and insertMany:
insertMany(docs: OptionalId<TSchema>[], options: BulkWriteOptions, callback: Callback<InsertManyResult<TSchema>>): void
For 99.1 the insertDocuments function was written to pass the result via callback
99.2 called insertDocuments, but apparently didn't care whether it succeeded or not, so it chose to ignore the result.

Can't save/create files using Store.js

So I wanted to save a file on the client storage using Store.js.
I can change the date using store.set and i can log it to console to see the change, but then it's supposed to be saved in app data where it's not created.
I tried to get the Path where it's being saved and it's :
C:\Users\USER\AppData\Roaming\stoma2/Categories.json
I noticed that there is a "/" so I tried :
C:\Users\USER\AppData\Roaming\stoma2\Categories.json
and :
C:/Users/USER/AppData/Roaming/stoma2/Categories.json
But all 3 of them didn't work.
This is my Store.js :
const fs = require('browserify-fs');
var fs2 = require('filereader'),Fs2 = new fs2();
const electron = window.require('electron');
const path = require('path');
class Store {
constructor(opts) {
// Renderer process has to get `app` module via `remote`, whereas the main process can get it directly
// app.getPath('userData') will return a string of the user's app data directory path.
//const userDataPath = (electron.app || electron.remote.app).getPath('userData');
var userDataPath = (electron.app || electron.remote.app).getPath('userData');
for(var i=0;i<userDataPath.length;i++){
if(userDataPath.charAt(i)=="\\"){
userDataPath = userDataPath.replace("\\","/");
}
}
// We'll use the `configName` property to set the file name and path.join to bring it all together as a string
this.path = path.join(userDataPath, opts.configName + '.json');
this.data = parseDataFile(this.path, opts.defaults);
console.log(this.path);
}
// This will just return the property on the `data` object
get(key) {
return this.data[key];
}
// ...and this will set it
set(key, val) {
this.data[key] = val;
// Wait, I thought using the node.js' synchronous APIs was bad form?
// We're not writing a server so there's not nearly the same IO demand on the process
// Also if we used an async API and our app was quit before the asynchronous write had a chance to complete,
// we might lose that data. Note that in a real app, we would try/catch this.
fs.writeFile(this.path, JSON.stringify(this.data));
}
}
function parseDataFile(filePath, data) {
// We'll try/catch it in case the file doesn't exist yet, which will be the case on the first application run.
// `fs.readFileSync` will return a JSON string which we then parse into a Javascript object
try {
return JSON.parse(Fs2.readAsDataURL(new File(filePath)));
} catch(error) {
// if there was some kind of error, return the passed in defaults instead.
return data;
}
}
// expose the class
export default Store;
There might be a probleme fith js.writeFile() (well that's the source of probleme).
and this is my call :
//creation
const storeDefCat = new Store({
configName: "Categories",
defaults: require("../data/DefaultCategorie.json")
})
//call for the save
storeDefCat.set('Pizza',{id:0,path:storeDefCat.get('Pizza').path});
For now if possible,I might need to find another way to save the file.
And i tried : fs : It doesn't work for me for some reason (I get strange errors that they don't want to be fixed..) .
If anyone has an Idea then please I would be grateful.
So I managed to fix the probleme, Why fs was sending me errors about undefined functions?Why file wasn't getting created ? It has NOTHING to do with the code it self, but the imports...
To clearify, I was using :
const fs = require('fs');
And the solution is to make it like :
const fs = window.require('fs');
Just adding window. fixed all the problems .Since it's my first time using electron I wasn't used to import from the window but it seems it's necessary.And more over...There was no posts saying this is the fix.

How to Pass a Command Line Argument in NodeJS?

I have a file structure, which I will enumerate for you in a moment. I have a web server, that initiates a command line process on a button press. I want to add in the option to run the server in a headless manner, using a command line argument. Is this the way I should be doing this? Here is my Project Structure.
/models
/model1
/model2
/model3
/routes
/index
/test
/users
/credentials
/adduser
/views
/same as routes. Route 'test' has no layout.
in index, or '/', I have a function, which takes several parameters, and is initiated via clicking a button on the index page. We are then forwarded through 'test/run', and render the 'index' view. The process continues to run in the terminal. I will now post an example of the function.
router.post('/run', ensureAuthenticated, function(req, res){
return res.redirect('/test/running')
});
// Get Homepage
router.get('/running', ensureAuthenticated, function(req, res){
console.log(res.locals.user);
// console.log(app.locals.user);
const var1 = res.locals.user.username;
const var2 = res.locals.user.username;
const var3 = res.locals.user.username;
const var4= res.locals.user.username;
const deets = {
var5,
var6
};
res.render('index');
dosomething(var1, var2, var3, var4, deets);
setInterval(dosomething, 10 * 1000);
})
});
So what do you guys think? How would I be able to implement the passing of var1-6, through the command line? I would greatly appreciate any help from here.
I am running on Windows right now, but the target server is for Ubuntu systems.
In node.js you can pass CLI arguments using build in process variable
for examples
// test.js
var args = process.argv;
console.log(args[0]); // it will give the node executable path
console.log(args[1]); // it will give current file name
console.log(args[2]); // cli arguments start index
now running the code
$ node test.js hello
/usr/bin/node
/home/blackdaemon/test.js
hello
If you like a pattern like "-arg" "value" try this:
var getArgs = function(){
var arr = {};
var last;
process.argv.forEach((a, idx) => {
if(idx > 1){
if(last){
arr[last] = a;
last = undefined;
}
else if(!last && a.match(/-\w+/))
last = a;
}
})
return arr;
}
The result should be:
$ node index no valid command -ar3 dsds -arg1 323
{ '-ar3': 'dsds', '-arg1': '323' }

Store output of shell command in sqlite

If I execute a certain shell command in node js, the output is on the console. Is there a way I can save it in a variable so it can be POST to Sqlite database.
const shell = require('shelljs');
shell.exec('arp -a');
In this scenario, I want to store the IP address of a specific MAC/Physical address into the database. How can this be done?
Any help would be much appreciated. Thank you
You need to get the output of the command you're passing to exec. To do that, just call stdout, like this:
const shell = require('shelljs');
const stdout = shell.exec('arp -a').stdout;
Then just parse that output to get your ipaddress:
const entries = stdout.split('\r\n');
// entries sample
[ '',
'Interface: 10.17.60.53 --- 0xd',
' Internet Address Physical Address Type',
' 10.11.10.52 6c-4b-90-1d-97-b8 dynamic ',
' 10.10.11.254 xx-yy-53-2e-98-44 dynamic ']
Then you can filter your wanted address with some more manipulation.
EDIT:
To get the ip address, you could do:
let ipAddr = null;
for (let i = 0; i < entries.length; i++) {
if (entries[i].indexOf('6c-4b-90-1d-97-b8') > -1) {
ipAddr = entries[i].match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/)[0];
break;
}
}
console.log(ipAddr); // '10.11.10.52'
I'm merely copy pasting from the docs. You should research more.
You need to add a listener to stdout
var child = exec('arp -a', {async:true});
child.stdout.on('data', function(data) {
/* ... do something with data ... */
});
Or adding the callback directly when calling exec
exec('some_long_running_process', function(code, stdout, stderr) {
console.log('Exit code:', code);
console.log('Program output:', stdout);
console.log('Program stderr:', stderr);
});
You can access the result of the command run using shell.exec with the .output property. Try the code below.
var shell = require('shelljs');
var result = shell.exec('arp -a').output;
If you don't want the result in the console, you can specify the silent option.
var result = shell.exec('arp -a', {silent: true}).output;
Now, you can use regular expressions to extract ip and mac address from the result.
I am getting the result of the command like below:
? (xxx.xxx.xxx.xxx) at xx:xx:xx:xx:xx:xx [ether] on eth0
? (yyy.yyy.yyy.yyy) at yy:yy:yy:yy:yy:yy [ether] on eth0
You can use the following code to extract ip and mac.
var res = result.split("\n").map(function(item){
return item.match(/\((\d+\.\d+\.\d+\.\d+)\) at (..:..:..:..:..:..)/);
});
console.log(res[0][1]); //IP of first interface
console.log(res[0][2]); //MAC of first interface
console.log(res[1][1]); //IP of second interface
console.log(res[1][2]); //MAC of second interface
NOTE
I was not able to find the .output property in the documentation but trying the shell.exec function in the node console revealed it.
The .stdout property or the exec function mentioned in other answers doesn't work for me. They are giving undefined errors.

Passing Argv to javascript form scala with JavaScript Engine and Trireme

I'm trying some server-side rendering with scala, play framework and react.js
At the moment I can render js from scala using js-engine (https://github.com/typesafehub/js-engine) but I want to give the js code some arguments (so I can do routing). This is what I have:
def app(route: String) = serverSideWithJsEngine(Trireme.props(), route)
private def serverSideWithJsEngine(jsEngine: Props, route: String) = Action.async { request =>
import akka.pattern.ask
val serverside=Play.getFile("target/web/public/main/serverSide.js")
implicit val timeout = Timeout(5.seconds)
val engine = Akka.system.actorOf(jsEngine, s"engine-${request.id}")
for {
result <- (engine ? Engine.ExecuteJs(
source = new File(serverside.toURI),
args = List(route),
timeout = timeout.duration
)).mapTo[JsExecutionResult]
} yield {
Ok(views.html.app(Html(new String( result.output.toArray, "UTF-8")
)))
}
}
This code renders the app but in theory, args = List(route) should give me "route" in the process.argv array from JS but I get an empty array.
Maybe is a bug from js-engine not passing args?? I don't understand why this code doesn't work...
Thanks!

Categories