Mongoose: How to add multiple plugins - node.js

In Mongoose, I've never actually seen an example of setting multiple Mongoose plugins on a schema.
All I ever see is
schema.plugin(mongooseSearchPlugin);
How does one go about adding another plugin to that? e.g. mongoosePaginatePlugin?

Unfortunately mongoose doesn't support initializing multiple plugins at once. So the only option is to call schema.plugin(...) multiple times.
You can can call the function multiple times to initialize all your plugins like this:
schema.plugin(mongooseSearchPlugin);
schema.plugin(mongoosePaginatePlugin);
Alternatively, if you store your functions in an iterable (something like an array) you can just iterate over each item and initialize it that way. Something like this:
const myPlugins = [ mongooseSearchPlugin, mongoosePaginatePlugin ];
myPlugins.forEach(plugin => schema.plugin(plugin));
// Or you can you block style
myPlugins.forEach((plugin) => {
schema.plugin(plugin);
});
Depending on how many plugins you're using this might make your code shorter. Ultimately it's a styling choice.
Hope this explanation helped.

Simply call schema.plugin multiple times

Related

How to use schedule?

I've seen quite a few examples of 'schedule' being used like this:
Timer().schedule(1000) {
// code to execute after delay
}
However, when I try to use it like this the function needs me to supply some sort of 'TimerTask' and I haven't seen anything about that.
So my question is how do you properly use schedule?

Ensure a Callback is Complete in Mongo Node Driver

I am a bit new to JavaScript web dev, and so am still getting my head around the flow of asynchronous functions, which can be a bit unexpected to the uninitiated. In my particular use case, I want execute a routine on the list of available databases before moving into the main code. Specifically, in order to ensure that a test environment is always properly initialized, I am dropping a database if it already exists, and then building it from configuration files.
The basic flow I have looks like this:
let dbAdmin = client.db("admin").admin();
dbAdmin.listDatabases(function(err, dbs){/*Loop through DBs and drop relevant one if present.*/});
return await buildRelevantDB();
By peppering some console.log() items throughout, I have determined that the listDatabases() call basically puts the callback into a queue of sorts. I actually enter buildRelevantDB() before entering the callback passed to listDatabases. In this particular example, it seems to work anyway, I think because the call that reads the configuration file is also asynchronous and so puts items into the same queue but later, but I find this to be brittle and sloppy. There must be some way to ensure that the listDatabases portion resolves before moving forward.
The closest solution I found is here, but I still don't know how to get the callback I pass to listDatabases to be like a then as in that solution.
Mixing callbacks and promises is a bit more advanced technique, so if you are new to javascript try to avoid it. In fact, try to avoid it even if you already learned everything and became a js ninja.
Dcumentation for listDatabases says it is async, so you can just await it without messing up with callbacks:
const dbs = await dbAdmin.listDatabases();
/*Loop through DBs and drop relevant one if present.*/
The next thing, there is no need to await before return. If you can await within a function, it is async and returns a promise anyway, so just return the promise from buildRelevantDB:
return buildRelevantDB();
Finally, you can drop database directly. No need to iterate over all databases to pick one you want to drop:
await client.db(<db name to drop>).dropDatabase();

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.

Calling a function that returns a AsyncIterableIterator without using "for await" block

I'm writing an AWS Lambda function in TypeScript using the Node.js runtime. I'm using a "batchDelete" function from a DynamoDB ORM library which returns an AsyncIterableIterator type.
According to the documentation here https://github.com/awslabs/dynamodb-data-mapper-js#batchDelete, I should invoke the method with a for await loop like this:
for await (const found of mapper.batchDelete(toRemove)) {
// items will be yielded as they are successfully removed
}
This all works great but the problem comes in where if I enable ESLint on my project. The default rules throw an error because the for await block is empty. I also get a warning because the found constant is never used. I have no use for the found constant and don't want to log it. I was wondering if there was another way to call an AsyncIterableIterator function where we disregard what is returned and don't have the empty block?
If you don't care about the results of the iteration, then you should probably just do something like this:
await Promise.all(toRemove.map(item => mapper.delete(item));
To use the mapper.batchDelete(toRemove) result more directly, you have to allow for multiple levels of promises. Perhaps you could do this:
await Promise.all(await mapper.batchDelete(toRemove)[Symbol.asyncIterator]());
In doing this, await mapper.batchDelete(toRemove)[Symbol.asyncIterator](), that would get you the default async Iterator and then passing it to Promise.all() would iterate it to get an iterable of promises. Unfortunately, in building it to make this easier:
for await (const found of mapper.batchDelete(toRemove))
they made it a bit more difficult to just get an array of promises out of it.
FYI, here's a link to the code for the .batchDelete() method if you want to look at how it's implemented.

Does origen support 93k multi_bin feature?

The examples for generating tests in the testflow create stop_bins. However there were no examples of how to generate the 93k multi_bin node. Does this feature exist in the current origen-sdk?
output node looks like this in 93k .tf file
if #FLAG then
{
multi_bin;
}
else
{
}
There is currently no direct support for creating multi_bin nodes, though in time I do expect that it will be added as a result of this effort to add support for limits tables.
In the meantime though, there is the ability to render any text and this can be used to generate what you want.
To generate the above example you could do:
if_flag :flag do
render 'multi_bin;'
end
This will also work with in-line conditions, this is the same:
render 'multi_bin;', if_flag: :flag
Additionally, on_pass and on_fail will accept a render option:
func :my_test, on_fail: { render: 'multi_bin;' }
Obviously that is creating something that will not be able to translate to other tester platforms, so the advice is to use render sparingly and only as a get out of jail card when you really need it.
Also note that for these examples to work you need at least OrigenTesters 0.11.1.

Resources