Cannot return method using module exports - javascript

I am trying to make a database file that delivers connection, model etc for mongoose (MongoDb).
So when I return the Mongoose Model, the create method becomes
"undefined".
database.js
//model connection
exports.MongoModel = async function ({connectionName, collection, schema}){
//get connection data
const databaseData = connectionsArray[connectionName];
//create url
const mongoUrl = `${dbUrl}${databaseData.databaseName}`;
//connection
const connection = Mongoose.createConnection(mongoUrl, databaseData.options);
//model with schema
const Model = connection.model('files',schema);
console.log(Model.create);// displays [Function: create] in console
//return model
return Model
}//MongoModel ends
When imported to the other file
FileUploads.js
const { MongoModel } = require('#src/config/database');
const FilesModel = MongoModel({connectionName:'files', collection: 'files', schema: FilesSchema});
console.log(FilesModel); // Displays Promise { Model { files } }
console.log(FilesModel.create); // Displays undefined
Note: I am very new to this platform so please pardon me typo's.

In your code 'MongoModel' references an async function which always returns a Promise. That is why you see Promise { Model { files } } when you log the object to your console. Two things you can do are:
Option 1: Remove the 'async' key word from your function declaration. This way your function returns your model object instead of a promise.
Option 2: Add a callback to get the data returned by the promise as shown below:
MongoModel({connectionName:'files', collection: 'files', schema: FilesSchema})
.then((FileModel) => {
console.log(FileModel.create); // should display [Function: create]
});

Well try it like this:
//model connection
function MongoModel({connectionName, collection, schema}){
//get connection data
const databaseData = connectionsArray[connectionName];
//create url
const mongoUrl = `${dbUrl}${databaseData.databaseName}`;
//connection
const connection = Mongoose.createConnection(mongoUrl, databaseData.options);
//model with schema
const Model = connection.model('files',schema);
console.log(Model.create);// displays [Function: create] in console
//return model
return Model
}//MongoModel ends
module.exports = { MongoModel }
You need to export an Object with your MongoModel in it. Now you should be able to destructure it at the import statement.
And i dont see a reason to use async here

Related

Mongoose keep duplicate elements

I have a function that create guild entry for DiscordJS, but when the script start and also if the function is called multiple times, it create around 400 duplicate documents, it create by ID and the ID is unique, so it's not normal
My schema structure only have a ID type String and unique is true
client.createGuild = async guild => {
const exist = await Guild.findOne({ id: guild.id });
if(!exist) {
await Guild.create({ id: guild.id }); // new Guild().save() keep duplicate too
}
}
It look like the if statement doesn't exist
const Schema = mongoose.Schema;
const FooSchema = new Schema({
id: { type: String, index: true, unique: true }
});
const Foo = mongoose.model('Foo', FooSchema);
Foo.createIndexes();
If collection already exists. Create index manually to the collection via atlas or cmd.
You can combine getData and createData functions to one. Here is the example:
const mongoose = require('mongoose');
async function getData(Guild, guild) {
if (!mongoose.connection.readyState) await mongoose.connect('MONGO_URL'); // In case you haven't connect to database
const data = await Guild.findOne({ id: guild.id }); // get data from database
if (!data) {
return new Guild({
id: guild.id,
}); // If no data exists for the guild, return new model
}
return data; // If the data already exists, return that
}
Now if you want to get data from mongodb you just call the function. It automatically create and save a new one if there is not.
Comment if you still have any problem or you have got what you need.
Make sure to call the function with await or it won't return the data.

Mongoose - find() not returning anything when no parameters are passed, but returns data when parameters are passed

I have the following model in teamMembers.js:
const { Schema, model } = require('mongoose');
const teamMembersSchema = new Schema({
uid: String,
name: String,
hours: Number
})
const TeamMembers = model('teamMembers', TeamMembersSchema);
module.exports = TeamMembers;
I've created the following endpoints in teamMemberRoute.js:
const TeamMembers = require('./models/teamMembers');
module.exports = (app) => {
app.get('/api/pods/teamMembers/:uid', async (req, res) => {
let teamMember = await TeamMembers.find( {'uid': req.params.uid } );
return res.status(200).send(teamMember);
});
app.get('/api/pods/teamMembers', async (req, res) => {
let teamMembers = await TeamMembers.find();
return res.status(200).send(teamMembers);
});
}
The first endpoint (/api/pods/teamMembers/:uid) works just fine - when I pass a uid it returns documents specific to that uid in the TeamMember collection.
The second endpoint should return all documents from the TeamMember collection since no parameters are passed. However, when the request is executed, only [] is returned. We know for a fact that documents exist in the TeamMember collection, since the first endpoint returns data from that collection based on the uid parameter that is passed.
I'm stumped on this. Any ideas? I don't think there is anything wrong with my model since I am able to execute the first endpoint with no issues.
Express executes code from top to button, and that is the reason for this issue. It will match your first endpoint and assume that uid is null. Just change the order of defined endpoints, like this:
module.exports = (app) => {
app.get('/api/pods/teamMembers', async (req, res) => {
let teamMembers = await TeamMembers.find();
return res.status(200).send(teamMembers);
});
app.get('/api/pods/teamMembers/:uid', async (req, res) => {
let teamMember = await TeamMembers.find( {'uid': req.params.uid } );
return res.status(200).send(teamMember);
});
}

FindAll inside model hooks 'afterFind' not working using sequilize in nodejs

I have a project in nodejs using sequelize.
I am tring to do a FindAll inside a model but I am getting this error:
Cannot read property 'findAll' of undefined
I import the models like this:
const db = require('./index');
And in the model hooks I am trying to do this:
hooks: {
afterFind: async function(User){
let ranks_db = await db.rank.findAll({ });
// let rank = await checkRank(User.exp);
User['exp'] = {
value: User.exp,
rank
};
return User;
}
}
The findAll it is working in the controller but not in the model
. I want to know if it is posible to do a FindAll inside a model
It is likely that you have a circular dependency between your models and that db.rank has not been populated yet when the Model you are showing here is constructed. Instead of importing the models via require you can reference them from the sequelize variable that is passed into the Model.
module.exports = function Model(sequelize, DataTypes) {
return sequelize.define('user', { /* columns */ }, {
hooks: {
afterFind: async function(user) {
const ranks = await sequelize.models.rank.findAll();
// user.ranks = ranks;
},
}
});
}

Setting up database for e2e testing fails: E11000 duplicate key error collection

I am having some troubles trying to set up a database for testing purposes. The data stored in the database should be removed an re-populated for each test. I am currently doing the following:
db.js
const mongoose = require('mongoose');
// a Mongoose model describing an entity
const Entity = require('entity-model');
// entities.mock is an array containing entity objects.
const mockedEntities= require('./entities.mock');
function setUp() {
Entities.collection.insertMany(mockedEntities);
}
function breakDown() {
mongoose.connection.on('connected', () => {
mongoose.connection.db.dropDatabase();
});
}
module.exports = { setUp, breakDown };
Then in my test.js:
const db = require('./db');
describe('e2e tests to make sure all endpoints return the correct data from the database', () => {
beforeEach(async () => {
await db.breakDown();
db.setUp();
});
it('should check store-test-result (UR-101)', (done) => ...perform test);
it('should check store-nirs-device (UR-102)', (done) => ...perform test);
});
It seems like I am not emptying out the database before re-populating it correctly. Any advise as to what could be the cause?
I ended up doing:
beforeEach(async () => {
await MyEntity.collection.drop();
await MyEntity.collection.insertMany(mockedMyEntity);
});
This solved my issue.
In case this result in an Mongo Error ns not found you need to explicitly create the collection in the database before dropping it. This happens if the collection does not exist. You can do this by adding a before:
before(async () => {
await MyEntity.createCollection();
});
Do not set option: autoCreate to true in you model as this should not be set to false in production according to https://mongoosejs.com/docs/guide.html#autoCreate.

Pull knexnest call out to file of its own to prevent duplication

I'm using knexnest as follows:
const customerProducts = knex.select([
'CustomerProduct.id AS _id',
'CustomerProduct.price AS _price',
'CustomerProduct.active AS _active',
'CustomerProduct.customer_id AS _customerId',
'CustomerProduct.product_id AS _productId',
'customer.id AS _customer_id',
'customer.name AS _customer_name',
])
.from('customer_products AS CustomerProduct')
.innerJoin(
'customers AS customer',
'CustomerProduct.customer_id',
'customer.id',
)
.where(whereClause);
const result = knexnest(customerProducts).then(data => data);
return result;
I'll likely be creating several other queries with which I'll then use knexnest to create a nested model. Is there a way that I can pull knexnest(customerProducts).then(data => data); out to a different file so that I could just call it rather than adding that line with every query and also having to import knexnest into every file?
To achieve what you're trying to accomplish, the simplest way would be to export a function that returns the promise generated by knexnest. Then, import that function in the main file and call it. You can either use async/await syntactic sugar or a .then. It's important that you use one knex connection object throughout your application to leverage knex's connection pool. Therefore, we must pass it into your function so the other file can access the established connection object.
File 1
const Knex = require('knex');
// import the function getCustomerProducts using destructuring
const { getCustomerProducts } = require('<File 2's Path>');
// initialize knex & set up knex database connection
const knex = Knex({
client: 'postgres',
connection: process.env.DATABASE_URL
});
// pseudo-code - note: await can only be called within an async function
// pass knex connection object into function to leverage knex's connection pooling
const products = await getCustomerProducts(knex);
File 2
const knexnest = require('knexnest');
const getCustomerProducts = knex => {
const customerProducts = knex.select([
'CustomerProduct.id AS _id',
'CustomerProduct.price AS _price',
'CustomerProduct.active AS _active',
'CustomerProduct.customer_id AS _customerId',
'CustomerProduct.product_id AS _productId',
'customer.id AS _customer_id',
'customer.name AS _customer_name',
])
.from('customer_products AS CustomerProduct')
.innerJoin(
'customers AS customer',
'CustomerProduct.customer_id',
'customer.id',
)
.where(whereClause);
return knexnest(customerProducts);
};
// named export of the function getCustomerProducts
module.exports.getCustomerProducts = getCustomerProducts;

Categories