scope of callback in a .connect() (nodejs, mongodb) - node.js

im trying to use a global database object to handle the data on my nodejs server. It shall contain all data of all connected users. Ready to be accessed anytime out of ram.
Therefore i created a module:
function Database() {
var MongoClient = require('mongodb').MongoClient;
this.dbcon; //database connection
// Connect to the db
MongoClient.connect("mongodb://localhost:27017/dbname", this.givedatabasevars);
};
As i want to reuse the database connection instead of opening new ones everytime i want to access the propertys of my object using the callback function and give them the connection object:
Database.prototype.givedatabasevars = function(err, getdbcon) {
if(err) {console.log(err)};
this.dbcon = getdbcon; //not working(scoped changed when used as callback?)
db.dbcom = getdbcon; //also not working(db object maybe not there yet as its a callback in constructor?)
};
I create the object using this globaly:
var Database = require('./node_modules/database/database.js');
var db = new Database();
Now im pretty new to nodejs and javascript all together. I tryed to get my head around how to access the objects scope, but from within the callback i cant even access the global scope.
Is this even possible?
Its the same for what to do with the data when using .find() with a callback. How do i get the data out of there to be used by my application? I need to store it, not to use it directly.
Regards,
Michael

You can access the global object using the global variable. Do console.log(this) on a plain file to see all the globals.
And for mongodb maybe mafintosh/mongojs can give you a more shareable interface. In fact I think with that you don't even need to have a global necessarily ;)

Related

Express4: Storing db instance

In express4, is it bad practice to store the db instance in app.locals or store it using app.set? Because I was thinking about it, since I will need it throughout my app it will be easier to access.
It should work just fine and no, I don't think it's bad practice (at least not horrible) - after all, app.locals is intended to provide you a safe place to put your global values.
However, using Express to store miscellaneous global values like this does result in your application being tightly bound to Express. If you ever decide that you want to remove Express and replace it with something else, you're going to have to hunt down and change all those references to app.local that are now scattered throughout your code.
If you want to avoid this, one simple pattern is to create a module exporting the value you want - this allows you to keep all the associated code in one place and import it whenever you need it. For example:
// modules/database.js
// initialize the database
const db = initializeDatabase();
// export a "getter" for the database instance
export const get = () => db;
Then, when you want to use the database instance:
// index.js
// import the database "getter"
import { get } from './modules/database';
// perform a query
const rows = get().query('SELECT * FROM table');
Just import modules/database anywhere you want to use the database.

"Global" module object in Node.js

I have a module for connecting to my DB and perform actions.
Then in my main script (app.js) I instantiate it like
var DBConn = require('./common/DBConn');
And from that script it works fine. But then I've got some other scripts that handle routes, and I want to perform some DB stuff on those, but if I use DBConn it returns an error saying "DBConn is not defined".
Then I can just instantiate another DBConn in these other js files, but this would mean I am creating a connection for each file, right? But I want these other scripts to use the DBConn object from the app.js, so that I'm not constantly establishing a connection to the DB and then closing it... (unless this is a good idea, but to me it makes more sense to have just one "global" object dealing with the connection over all the app and that's it).
(BTW: I'm using Express)
You want to require() your module in each file. Node will cache the module.
Typically, the context of a DB connection is abstracted away behind stores or repositories and your other modules interact with those. In cases where people are directly requiring modules like mongoose, they'll require mongoose everywhere but only call the connection code within their main application entry point (app.js/server.js/whatever).
https://nodejs.org/api/modules.html#modules_caching
Modules are cached after the first time they are loaded. This
means (among other things) that every call to require('foo') will get
exactly the same object returned, if it would resolve to the same
file.
Multiple calls to require('foo') may not cause the module code to be
executed multiple times. This is an important feature. With it,
"partially done" objects can be returned, thus allowing transitive
dependencies to be loaded even when they would cause cycles.
If you want to have a module execute code multiple times, then export
a function, and call that function.
You could use a singleton to solve this issue for you. Please remember however that singletons come with their own set of problems (a good discussuon on singletons can be found here What is so bad about singletons?).
That said once you take into consideration the pro's and cons of singletons they can be a fantastic solution to exactly this problem.
Example:
// database.js
var singleton = function singleton() {
this.DbConnection = {};
function setup(database, username, password) {
this.DbConnection = MakeDbConnection()
};
};
singleton.instance = null;
singleton.getInstance = function(){
if(this.instance === null){
this.instance = new singleton();
}
return this.instance;
};
module.exports = singleton.getInstance();
This can then be called elsewhere in your application like so...
// main.js
var db = require("./database");
db.setup('db', 'root', 'pass');
db.DbConnection();
Once you have called db.setup() the first time, the db connection will be available just with the following:
// elsewhere.js
var db = require("./database");
db.DbConnection();

node-mongodb-native 2.X driver using to multiple databases

Is there a way to use multiple databases with a single connection to mongodb? I've found this:
https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html#open
but as best I can tell those docs are old as there does not appear to be an open method on the MongoClient? Do you actually need to establish multiple connections?
Thanks!
Found it:
http://mongodb.github.io/node-mongodb-native/2.0/api/Db.html#db
Here is their example
var MongoClient = require('mongodb').MongoClient,
test = require('assert');
MongoClient.connect('mongodb://localhost:27017/test', function(err, db) {
test.equal(null, err);
// Reference a different database sharing the same connections
// for the data transfer
var secondDb = db.db("integration_tests_2");
...
It is synchronous. Seems strange to me this method doesn't have the word "use" in it. Also seems strange it belongs to the db class. db.db('other_db').. a bit obscure. Did some tests, seems to work, so I'll mark this as the answer for anyone else that ends up here.

Node.js requiring a script but not running it

In Node.js, when you do
var otherscript = require('otherscript');
it runs the script upon the require
I am wondering if there is a way to "require" a script without running it, so that you can run it later when you want to.
Is there any good reason why not?
If you can edit the 'otherscript' (no one else is using that script) then you can simply enclose the whole code inside a function and add it to exports.
Example:
otherscript:
module.exports = function(){
//original code goes here
};
Then use as:
var otherscript = require('otherscript');
var obj = otherscript();
When you require a file or module, the return of that file/module is cached. In other words, it is really only executed once, and subsequent calls to require() of that file/module will only return a reference to the exact same object.
A common example of this is the Mongoose package, where calling require('mongoose') will return an instance of mongoose, on which you can call connect() to connect to the database. Calling require('mongoose') again in a different part of your program will return the same instance with the same database connection made available.

Extending MongoDB's "save" method in nodejs

In our app, we have a large document that is the source of most of our data for our REST api.
In order to properly invalidate our client-side cache for the REST api, i want to keep track of any modifications made to teh document. The best we came up with is to extend the mongo save command for the document to send off the notification (and then save as usual).
The question is, how does one actually do this in practice? Is there a direct way to extend mongo's "save" method, or should we create a custom method (i.e. "saveAndNotify") on the model that we use instead (which i would avoid if i can)?
[edit]
So in principle, i am looking to do this, but am having an issue not clobbering the parent save function();
mySchema.methods.save = function() {
// notify some stuff
...
//call mongo save function
return this.super.save();
};
Monkey patching the core mongo object is a bad idea, however it turns out mogoose has a middleware concept that will handle this just fine:
var schema = new Schema(..);
schema.pre('save', function (next) {
// do stuff
next();
});

Resources