MongoDB and Mocha - mongodb

Has anyone ever used async/await in their mocha tests?
I'm creating this simple test to check if my code successfully saves an object to the database:
const mocha = require('mocha');
const assert = require('assert');
const marioChar = require('../models/mariochar');
async function saveAMarioChar (paramname,paramweight) {
var char = new marioChar({
name: paramname,
weight: paramweight
});
const saveresult = await char.save()
return !saveresult.isNew;
}
describe(
'saving record',
() => {
it('Save a mariochar',
async () => {
const result = await saveAMarioChar('luigi',64);
assert(result)
}
)
}
)

Sorry for the trouble guys, this code is working fine, I used "mongooose" with a triple "o" on my schema creation.

Related

Making a welcome message an embed on discord.js

I have connected MongoDB to my discord.js code and have made a setwelcome command as per-server data so that each server can customize their own welcome message. Everything works great, I just want to know if there is any way that I can make the message appear as an embed? Here's the code:
//importing all the needed files and languages
const mongo = require('./mongo')
const command = require('./command')
const welcomeSchema = require('./schemas/welcome-schema')
const mongoose = require('mongoose')
const Discord = require('discord.js')
mongoose.set('useFindAndModify', false);
//my code is inside this export
module.exports = (client) => {
//this next line is for later
const cache = {}
command(client, 'setwelcome', async (message) => {
const { member, channel, content, guild } = message
//checking to see that only admins can do this
if (!member.hasPermissions === 'ADMINISTRATOR') {
channel.send('You do not have the permission to run this command')
return
}
//simplifying commands
let text = content
//this is to store just the command and not the prefix in mongo compass
const split = text.split(' ')
if (split.length < 2) {
channel.send('Please provide a welcome message!')
return
}
split.shift()
text = split.join(' ')
//this is to not fetch from the database after code ran once
cache[guild.id] = [channel.id, text]
//this is to store the code inside mongo compass
await mongo().then(async (mongoose) => {
try {
await welcomeSchema.findOneAndUpdate({
_id: guild.id
}, {
_id: guild.id,
channelId: channel.id,
text,
}, {
upsert: true
})
} finally {
mongoose.connection.close()
}
})
})
//this is to fetch from the database
const onJoin = async (member) => {
const { guild } = member
let data = cache[guild.id]
if (!data) {
console.log('FETCHING FROM DATABASE')
await mongo().then( async (mongoose) => {
try {
const result = await welcomeSchema.findOne({ _id: guild.id })
cache[guild.id] = data = [result.channelId, result.text]
} finally {
mongoose.connection.close()
}
})
}
//this is to simplify into variables
const channelId = data[0]
const text = data[1]
/*this is where the message sends on discord. the second of these 2 lines is what I want embedded
which is basically the welcome message itself*/
const channel = guild.channels.cache.get(channelId)
channel.send(text.replace(/<#>/g, `<#${member.id}>`))
}
//this is to test the command
command(client, 'simjoin', message => {
onJoin(message.member)
})
//this is so the command works when someone joins
client.on('guildMemberAdd', member => {
onJoin(member)
})
}
I know how to usually make an embed, but I'm just confused at the moment on what to put as .setDescription() for the embed.
Please advise.
If you just want to have the message be sent as an embed, create a MessageEmbed and use setDescription() with the description as the only argument. Then send it with channel.send(embed).
const embed = new Discord.MessageEmbed();
embed.setDescription(text.replace(/<#>/g, `<#${member.id}>`));
channel.send(embed);
By the way, if you are confused about how to use a specific method you can always search for the method name on the official discord.js documentation so you don’t have to wait for an answer here. Good luck creating your bot!

Error: Cannot find module 'react-bootstrap/lib/Breadcrumb'

I am following this tutorial: https://youtu.be/YPbgjPPC1d0 at 34:55 I am trying to use "truffle test", but keep getting Error: Cannot find module 'react-bootstrap/lib/Breadcrumb'
My code:
const { should, assert } = require('chai')
const { useReducer } = require('react')
const { Item } = require('react-bootstrap/lib/Breadcrumb')
const color = artifacts.require('./color.sol')
require('Chair')
useReducer(require('chai-as-promised'))
should()
contract ('color', (accounts) => {
describe('deployment', async () => {
It('deploys successfully', async () => {
contract = await color.deployed()
const address = contract.address
console.log(address)
assert.notEqual(address, '')
})
})
})
I am using Virtual Studio Code
Has anyone had similar problem or know how to fix it? Thanks

Mongoose/Mongodb, update each doc query, very slow

I have this update query in mongoose. It's 1600 posts and takes like 5 min to run.
What's the bottleneck? Am I using the wrong approach?
export const getAndStoreLatestKPI = async () => {
console.log("start kpi");
try {
const marketCaps = await getKPI();
const stocks = await mongoose.model("stock").find().exec();
for (const stock of stocks) {
const marketCap = marketCaps.find(
(marketCap) => marketCap.i === stock.insId
);
if (marketCap != null) {
const marketCapAdjustedVal =
stock.country === "Finland" ? marketCap.n * 10 : marketCap.n;
const update = {
marketCap: marketCapAdjustedVal,
};
console.log(marketCapAdjustedVal);
await mongoose
.model("stock")
.findOneAndUpdate({ insId: stock.insId }, { update });
}
}
console.log("done");
return Promise.resolve();
} catch (err) {
return Promise.reject(err);
}
};
export const getKPI = async (kpiId: number) => {
try {
const kpiFetch = await Axios.get(someurl);
return Promise.resolve(kpiFetch.data.values);
} catch (err) {
return Promise.reject(err);
}
};
So the main bottle neck is your for loop. for each stock item you perform several "expensive" actions such as data fetching from external API + a single update, and you're doing them 1 by 1.
What I would recommend you doing is looping on several items at once. similar to the idea multithreading.
There are several different solutions on how to do it in nodejs for example nodejs worker threads
However I personally use and recommend using bluebird which gives you this ability and many others straight out of the box.
Some sample code:
import Bluebird = require('bluebird');
const stocks = await mongoose.model("stock").find().exec();
await Bluebird.map(stocks, async (stock) => {
const marketCap = marketCaps.find(
(marketCap) => marketCap.i === stock.insId
);
if (marketCap != null) {
const marketCapAdjustedVal =
stock.country === "Finland" ? marketCap.n * 10 : marketCap.n;
const update = {
marketCap: marketCapAdjustedVal,
};
console.log(marketCapAdjustedVal);
await mongoose
.model("stock")
.findOneAndUpdate({ insId: stock.insId }, { update });
}
}, {concurrency: 25})
// concurrency details how many concurrent process run parallel. the heavier they are the less you want concurrent for obvious reasons.

Jest mongo concurrency error

Update This may be a bug in Jest - watching this issue here.
I am running Jest tests with Mongo as instructed in the Jest docs
When I run more than one test file at the time I get this error:
TypeError: Cannot read property 'getConnectionString' of undefined
3 | class MongoEnvironment extends NodeEnvironment {
4 | async setup () {
> 5 | this.global.__MONGO_URI__ = await global.__MONGOD__.getConnectionString()
6 | this.global.__MONGO_DB_NAME__ = global.__MONGO_DB_NAME__
7 |
8 | await super.setup()
at MongoEnvironment.setup (test/mongo-environment.js:5:57)
The only way I can run without error is with the --runInBand or --maxWorkers 1 option.
It doesn't matter what my tests are - I can do dummt tests in each file like:
test('Yo', () => {
})
So let's say I add this content to foo.spec.js and bar.spec.js in test/ dir and do jest test/ it will yield error.
My jest config:
module.exports = {
globalSetup: './test/setup.js',
globalTeardown: './test/teardown.js',
testEnvironment: './test/mongo-environment.js',
setupTestFrameworkScriptFile: './test/bootstrap.js',
testPathIgnorePatterns: ['/node_modules/', '/config/']
}
The setup, teardown and mongo-environment are the same as in Jest docs. My bootstrap file is the before/after hooks:
const { MongoClient } = require('mongodb')
let db
beforeAll(async () => {
connection = await MongoClient.connect(global.__MONGO_URI__)
db = await connection.db(global.__MONGO_DB_NAME__)
})
afterAll(async () => {
await connection.close()
await db.close()
})
Any idea what is going on?
Here are the other files for completness in case I made a booboo:
//setup.js
const MongodbMemoryServer = require('mongodb-memory-server')
const MONGO_DB_NAME = 'jest'
const mongod = new MongodbMemoryServer.default({ // eslint-disable-line new-cap
instance: {
dbName: MONGO_DB_NAME
},
binary: {
version: '3.2.19'
}
})
module.exports = function () {
global.__MONGOD__ = mongod
global.__MONGO_DB_NAME__ = MONGO_DB_NAME
}
// teardown.js
module.exports = async function () {
await global.__MONGOD__.stop()
}
//mongo-environment.js
const NodeEnvironment = require('jest-environment-node')
class MongoEnvironment extends NodeEnvironment {
async setup () {
this.global.__MONGO_URI__ = await global.__MONGOD__.getConnectionString()
this.global.__MONGO_DB_NAME__ = global.__MONGO_DB_NAME__
await super.setup()
}
async teardown () {
await super.teardown()
}
runScript (script) {
return super.runScript(script)
}
}
module.exports = MongoEnvironment
Note that the error is not 100% consistent - perhaps some kind of timing issue.
This is not just a Mongo thing. If I dump globals in my MongoEnvironment setup() method I can see that when running more than one test a whole bunch of Jest globals are missing.

How can I wrap sails-mongo db methods for profiling?

I'm trying to setup a sails hook with miniprofiler to help profile mongo usage. I'm struggling for how to wrap the db methods in a function that will execute the profile. I'm trying to do this via a user hook:
setupMiniprofilerMongo(req, res, next) {
const adapter = sails.hooks.orm.datastores.default.adapter;
const adapterPrototype = Object.getPrototypeOf(adapter);
const originalMethod = adapter.adapter.find;
methodPrototype.find = function profiledMongoCommand(connectionName, collectionName, options, cb) {
sails.log.info(`${collectionName}.find`);
return originalMethod.call(adapter, connectionName, collectionName, options, cb);
};
}
That causes the following error to be thrown:
TypeError: Cannot read property 'collections' of undefined
at Object.module.exports.adapter.find (/Users/jgeurts/dev/platform/node_modules/sails-mongo/lib/adapter.js:349:40)
at Object.profiledMongoCommand [as find] (/Users/jgeurts/dev/platform/config/http.js:234:37)
Any help would be appreciated. I tried to wrap the methods on mongodb package, but that doesn't seem to work either. :/
I got this working by wrapping waterline query methods. There is room for improvement, though.
setupMiniprofilerWaterline(req, res, next) {
const dbOperations = [
'count',
'create',
'createEach',
'define',
'describe',
'destroy',
'drop',
'find',
'join',
// 'native',
// 'registerConnection',
'update',
];
const waterlineMethodByModels = {};
const miniprofilerWaterline = () => {
return {
name: 'mongodb',
handler(req, res, next) {
if (!req.miniprofiler || !req.miniprofiler.enabled) {
return next();
}
const profiler = req.miniprofiler;
for (const modelName of _.keys(sails.models)) {
for (const dbOperation of dbOperations) {
const model = sails.models[modelName];
if (!model[dbOperation]) {
continue;
}
if (!waterlineMethodByModels[modelName]) {
waterlineMethodByModels[modelName] = {};
}
// Prevent wrapping a method more than once
if (waterlineMethodByModels[modelName][dbOperation]) {
continue;
}
waterlineMethodByModels[modelName][dbOperation] = true;
const originalMethod = model[dbOperation];
model[dbOperation] = function profiledMongoCommand(...args) {
const query = args && args.length ? args[0] : '';
const lastArg = args && args.length ? args[args.length - 1] : null;
const modelAndMethod = `${modelName}.${dbOperation}`;
if (lastArg && typeof lastArg === 'function') {
sails.log.debug(`mongo::${modelAndMethod} - ${JSON.stringify(query)}`);
const callback = args.pop();
const timing = profiler.startTimeQuery('mongodb', query ? JSON.stringify(query || '') : '');
// In general, the callstack is kind of useless to us for these profiles
// The model/db method is more useful in the miniprofiler UI
timing.callStack = `\n\nMethod: ${modelAndMethod}`;
return originalMethod.call(this, ...args, function profiledResult(...results) {
profiler.stopTimeQuery(timing);
callback(...results);
});
}
const methodResult = originalMethod.call(this, ...args);
const methodResultPrototype = Object.getPrototypeOf(methodResult);
const isDeferred = !!methodResultPrototype.exec;
// If methodResult is a Deferred object type, then the query method will be profiled above when the deferred is executed (with a callback)
// So we only care to log this if the methodResult is not a deferred object
if (!isDeferred) {
sails.log.warn(`Was not able to profile mongo::${modelAndMethod}. Maybe its a promise? query: ${JSON.stringify(query)}`);
}
return methodResult;
};
}
}
next();
},
};
};
miniprofiler.express.for(miniprofilerWaterline())(req, res, next);
},
The code is available as miniprofiler-waterline if you want to contribute/use it in your own projects