How to implement different middlewares for different monk's Manager instance? - node.js

I'm using monk (https://automattic.github.io/monk/) in order to do mongodb data manipulation.
Monk has a middleware mechanism, and we can simply invoke addMiddleware to add as many middleware as needed (https://automattic.github.io/monk/docs/middlewares.html)
It works well until I create two manager (https://automattic.github.io/monk/docs/manager/) instance. The middlewares of the two manager seems to polute each other.
So, I create a simple test in order to make sure the hypothesis.
Here is the test:
let db = monk('mongodb://localhost/test')
let softDb = monk('mongodb://localhost/other')
console.error(db._collectionOptions.middlewares === softDb._collectionOptions.middlewares)
And as my prior hypothesis, it yield true. Eventhough db and softDb are different objects, they seems to share the same _collectionOptions.middlewares. Probably monk's developer implement singleton pattern.
My question is: how could I make this softDb and db have different set of middlewares?
Thanks in advance.

I find a workaround. This is not an officially approved solution and I'm still seeking for a better solution. So, if any of you find a better solution, I'll approve your answer.
Since both softDb and db share the same set of middleware, then I deep-clone and re-assign both db._collectionOptions.middlewares. For deep-cloning purpose, I use this package: https://www.npmjs.com/package/clone.
The solution looks as follow:
let clone = require('clone')
let db = monk('mongodb://localhost/test')
db._collectionOptions.middlewares = clone(db._collectionOptions.middlewares)
let softDb = monk('mongodb://localhost/other')
softDb._collectionOptions.middlewares = clone(softDb._collectionOptions.middlewares)
// Here I can add different set of middlewares to db and softDb
// The middlewares of both manager will be independent to each other
console.error(db._collectionOptions.middlewares === softDb._collectionOptions.middlewares)
// Now, this will yield `false`
It is important to note that you have to copy the middlewares immediately after creating a manager instance.
I'm aware that some people might hate this solution. So, rather than down-voting this answer, please provide a better solution instead.

Related

mongoose optimistic concurrency - how to track changes on document when versioning error handling is needed

we have a big enterprise Node.JS application with multiple microservices that can in parallel access DB entity called context. At some moment we started to have concurrency issues, i.e. two separate microservices did load same context, did different changes and saved, resulting in loss of data. Because of this we have rewritten our DB layer to use mongoose with full optimistic concurrency enabled (via scheme option optimisticConcurrency). This work fine and now when we get version error we reload latest version of the context, reapply all the changes again and save. Problem is that this reapplication creates duplicities in code. Our general approach can be expressed by following pseudo code:
let document = Context.find(...);
document.foo = 'bar'
document.bar = 'foo'
try {
document.save()
} catch(mongooseVersionError) {
let document = Context.find(...);
// DUPLICATE CODE HERE, DOING SAME ASSIGNMENTS (foo, bar) AGAIN!
document.foo = 'bar'
document.bar = 'foo'
document.save()
}
What we would like to use instead is some automated tracking of all changes on document so that when we get mongoose versioning error we can reapply these changes automatically. Any idea how to do it in most elegant way? Does mongoose support something like this out of the box? I know that we could check in presave hook document attributes one by one via Document.prototype.isModified() method but this seems to me like quite worky and unflexible approach.

Expressjs higher order router vs appending to request

Let's say I want to pass to an ExpressJS route callback an object.
I know I can append to app:
// router.js
const getFoo = (req, res) => res.json(req.app.foo);
// index.js
const app = express();
app.foo = {};
app.get('/foo', getFoo);
or I can use a higher order function:
// router.js
const getFoo = foo => (req, res) => res.json(foo);
// index.js
const app = express();
const foo = {};
app.get('/foo', getFoo(foo));
Both are easy to write, extend and test.
But, I don't know the implications of the solutions and whether one is better.
Is there anyone knowing real differences between the two approaches?
I think the second solution is more correct, here's why.
imagine you get used to the first solution and one day you need to send something called post or get or anything with the name of app property and you forget that there is already a property named like that, so you override original property without even realizing and when you call app.post() program will crash.
Believe me, you don't want hours of research wasted on something like that and realizing that you simply overrode original method
Also, in my opinion, it's always a bad idea mutating original object which wasn't generated by you
As #vahe-yavrumian mentioned it is not a good idea to mutate the state of the object created by a third party library.
between you can also use app.get() and app.set() methods to pass any data to the other routers in the queue (seems those methods are there just for this purpose.)
more information at https://expressjs.com/en/api.html.
The second solution easily allows you to pass different value for foo on different routes, if you ever found a need to do that.
The first solution essentially puts the value on the app singleton, which has all the implications of using singletons. (And as mentioned by #Anees, for express specifically the app settings with get and set are the proper place to store this, not a custom property)

Arangodb: Can I call a user function from a user function?

Since user-functions are not allowed to have side-effects with respect to the data, I wondered if it's possible to call one function from the other.
I want to factor out common calculations.
One possible way I see is to use
var result = db._query("RETURN myfuncs::func(#a1, #a2)",
{'#a1': 'val1', '#a2': 'val2}, null, null).next();
But I would like another way if possible.
Each user function is completely standalone, meaning it is not possible to call a user function from within another.
This might change in the future, but this is the situation at the moment (ArangoDB 2.3/2.4/2.5).
I found the way how to do this. You can use db._query in user function, i.e.
var db = require('internal').db;
var resultFromOtherUserFunc = db._query('RETURN userFunction::MyFunction(#param)', {param: true}).toArray();

Breaking up node module code (for a library/api client)

I'm writing a node module to consume a REST API for a service. For all intents and purposes we might as well say it's twitter (though it's not).
The API is not small. Over a dozen endpoints. Given that I want to offer convenience methods for each of the endpoints I need to split up the code over multiple files. One file would be far too large.
Right now I am testing the pattern I will outline below, but would appreciate any advice as to other means by which I might break up this code. My goal essentially is to extend the prototype of a single object, but do so using multiple files.
Here's the "model" I'm using so far, but don't think is really a good idea:
TwitterClient.js
function TwitterClient(){
this.foo = "bar";
}
require("fs").readdirSync("./endpoints").forEach(function(file) {
require("./endpoints/" + file)(TwitterClient);
});
var exports = module.exports = TwitterClient;
endpoints/endpointA.js etc
module.exports = function(TwitterClient){
TwitterClient.prototype.someMethod = function(){
//do things here
}
}
The basic idea obviously is that any file in the endpoints folder is automatically loaded and the TwitterClient is passed in to it, so that it's prototype can be accessed/extended.
I don't plan to stick with this pattern because for some reason it seems like a bad idea to me.
Any suggestions of better patterns are very much appreciated, cheers

Mongoose connection/models: Need to always run on open?

I am using Mongoose 3 and the most obvious way to connect to database is
conn = mongoose.createConnection(...)
conn.on("open", ...)
Question is, do I need to define all my models in the open callback? If that is so, I will have to create a initMongoose.coffee that looks like
# initMongoose.coffee
mongoose = require "mongoose"
module.exports = mongoose.createConnection ...
# modelExample.coffee
conn = require "./initDatabase"
conn.on "open", ->
... define model?
modeule.exports = model # I think this does not work?
I think I read somewhere in Node docs that modules cannot be defined in a callback like that?
Since I am only using 1 connection, I think I can use
mongoose.connect ...
Which doesnt accepts any callbacks so I suppose is synchronous? Can I define all my models and thus queries right after connect()? It works at the moment, but it might be because its fast enough.
Mongoose buffers up commands until it is finished connecting, so you can treat it like it's synchronous and define your models and start using the library whenever you want; only once you want to start actually inserting or retrieving data do you need to make the connection.

Resources