Creating/saving Loopback model programmatically - node.js

I am trying to use
// item is some string representing model name
const Model = app.models[item];
Model.create([array of model data],{options}, function(a, b, c){
});
but this API is giving me hell, it seems to fire the callback inconsistently if at all, and also, {a,b,c}, seem to be totally inconsistent, in other words, Model.create does not seem to fire a standard error first callback and I simply cannot figure out what it is passing back, seems to be very inconsisent.
I filed an issue on Github for Loopback on this, but I am wondering if there is a better API for programmatically creating models like this.
I am trying to seed our test database with data.

There is no second optional parameter.
Model.create({propA: value /*, etc */}, function(err, results){
});

Related

Firestore: get document back after adding it / updating it without additional network calls

Is it possible to get document back after adding it / updating it without additional network calls with Firestore, similar to MongoDB?
I find it stupid to first make a call to add / update a document and then make an additional call to get it.
As you have probably seen in the documentation of the Node.js (and Javascript) SDKs, this is not possible, neither with the methods of a DocumentReference nor with the one of a CollectionReference.
More precisely, the set() and update() methods of a DocumentReference both return a Promise containing void, while the CollectionReference's add() method returns a Promise containing a DocumentReference.
Side Note (in line with answer from darrinm below): It is interesting to note that with the Firestore REST API, when you create a document, you get back (i.e. through the API endpoint response) a Document object.
When you add a document to Cloud Firestore, the server can affect the data that is stored. A few ways this may happen:
If your data contains a marker for a server-side timestamp, the server will expand that marker into the actual timestamp.
Your data data is not permitted according to your server-side security rules, the server will reject the write operation.
Since the server affects the contents of the Document, the client can't simply return the data that it already has as the new document. If you just want to show the data that you sent to the server in your client, you can of course do so by simply reusing the object you passed into setData(...)/addDocument(data: ...).
This appears to be an arbitrary limitation of the the Firestore Javascript API. The Firestore REST API returns the updated document on the same call.
https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents/patch
I did this to get the ID of a new Document created, and then use it in something else.
Future<DocumentReference<Object>> addNewData() async {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final CollectionReference _userCollection = _firestore.collection('users');
return await _userCollection
.add({ 'data': 'value' })
.whenComplete(() => {
// Show good notification
})
.catchError((e) {
// Show Bad notification
});
}
And here I obtain the ID:
await addNewData()
.then((document) async {
// Get ID
print('ID Document Created ${document.id}');
});
I hope it helps.

Koa-router getting parsed params before hitting route

I'm using koa2 and koa-router together with sequelize on top. I want to be able to control user access based on their roles in the database, and it's been working somewhat so far. I made my own RBAC implementation, but I'm having some trouble.
I need to quit execution BEFORE any endpoint is hit if the user doesn't have access, considering endpoints can do any action (like inserting a new item etc.). This makes perfect sense, I realize I could potentially use transactions with Sequelize, but I find that would add more overhead and deadline is closing in.
My implementation so far looks somewhat like the following:
// initialize.js
initalizeRoutes()
initializeServerMiddleware()
Server middleware is registered after routes.
// function initializeRoutes
app.router = require('koa-router')
app.router.use('*', access_control(app))
require('./routes_init')
routes_init just runs a function which recursively parses a folder and imports all middleware definitions.
// function initializeServerMiddleware
// blah blah bunch of middleware
app.server.use(app.router.routes()).use(app.router.allowedMethods())
This is just regular koa-router.
However, the issue arises in access_control.
I have one file (access_control_definitions.js) where I specify named routes, their respective sequelize model name, and what rules exists for the route. (e.g. what role, if the owner is able to access their own resource...) I calculate whether the requester owns a resource by a route param (e.g. resource ID is ctx.params.id). However, in this implementation, params don't seem to be parsed. I don't think it's right that I have to manually parse the params before koa-router does it. Is anyone able to identify a better way based on this that would solve ctx.params not being filled with the actual named parameter?
edit: I also created a GitHub issue for this, considering it seems to me like there's some funny business going on.
So if you look at router.js
layerChain = matchedLayers.reduce(function(memo, layer) {
memo.push(function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
ctx.routerName = layer.name;
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);
What it does is that for every route function that you have, it add its own capturing layer to generate the params
Now this actually does make sense because you can have two middleware for same url with different parameters
router.use('/abc/:did', (ctx, next) => {
// ctx.router available
console.log('my request came here too', ctx.params.did)
if (next)
next();
});
router.get('/abc/:id', (ctx, next) => {
console.log('my request came here', ctx.params.id)
});
Now for the first handler a parameter id makes no sense and for the second one parameter did doesn't make any sense. Which means these parameters are specific to a handler and only make sense inside the handler. That is why it makes sense to not have the params that you expect to be there. I don't think it is a bug
And since you already found the workaround
const fromRouteId = pathToRegexp(ctx._matchedRoute).exec(ctx.captures[0])
You should use the same. Or a better one might be
var lastMatch = ctx.matched[ctx.matched.length-1];
params = lastMatch.params(ctx.originalUrl, lastMatch.captures(ctx.originalUrl), {})

Unexpected performance issue

I've recently written a nodejs package अनुमार्गाक (Anumargak) which is used for HTTP routing. I'm facing a weird performance issue.
It has a method on to register a route and find to find registered route.
var anumargak = Anumargak();
anumargak.on("GET",'/some/url',fn);
anumargak.find("GET",'/some/url');
When a user calls on method it first calls find method to check if the route is already registered otherwise saves the route information in 2d array. When the user calls find method, it just look for an entry in 2d array.
Anumargak.prototype.on = function(method,url,fn){
if(this.find(method,url)){
this.count --;//count of unique registered routes.
}
this.count +=1;
this._on(method,url,fn);//_on method has actual logic of saving route information
}
Anumargak.prototype.find = function(method,url){
var result = this.staticRoutes[method][url];
if(result) return result.fn;
else{
//handles dynamic routes
}
return this.defaultFn;
}
find method has no dependency on on method. But when I call find method from on method, performance of find method decreases to half. I'm calling on method only once and testing the performance of find method. What can be the possible reason?
I'm using node v9.5.0.
I'm not sure what was the issue with performance. But calling this.find() was incorrect. Because this.find accepts actual URL whereas registered URLs can have regex or param detail.
Hence I've rewritten the code to fix the issue which solved performance as well.

Loopback context returning null in afterRemote method

I am newbie to loopback, I have written a function for signup and
executing on beforeRemote. Here I can able to access loopback context. But after user created I am executing another function to send verification link using afterRemote, here loopback context returning null value.
function signup(){
const lbCtx = LoopBackContext.getCurrentContext;
const details = lbctx().get('details');
//here it's working
}
function sendVerificationEmail(){
const lbCtx = LoopBackContext.getCurrentContext;
const details = lbctx().get('details');
//here not working
}
Users.beforeRemote('create', (ctx) => signup(ctx));
Users.afterRemote('create', (ctx) => sendVerificationEmail(ctx));
can anyone help me to achieve this.
There is a documented issue with the way the current context is handled in LoopBack.
Unfortunately it seems that the library they used to support this feature called continuation-local-storage is not entirely reliable and sometimes the context is not properly passed around so you get a null value instead.
There's a warning in the docs stating this and links to different workarounds, since there's no unified solution yet.
Note: One issue I see with your code (although it might be a typo) is that in the signup() method you are doing get() instead of set(). Just in case you didn't notice.

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