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

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;
},
}
});
}

Related

Cannot return method using module exports

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

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.

Non CRUD Route in FeathersJS

I have a service results that handles all CRUD Operations for the results service in feathersjs. How would I create a route /results/:id/hr_bar_graph which basically fetches the result at that particular id and uses the resulting data to create an bar graph.
My code currently is:
module.exports = function (app) {
const Model = createModel(app);
const paginate = app.get('paginate');
const options = {
name: 'results',
Model,
paginate
};
// Initialize our service with any options it requires
app.use('/results', createService(options));
app.use('/results/:id/hr_bargraph_image', {
find(id, params){
this.app.service('results').get(id)
.then(function(response){
console.log(response);
})
.cathc(function(error){
console.log(error);
})
return Promise.resolve({
imageData: ''
});
}
});
// Get our initialized service so that we can register hooks and filters
const service = app.service('results');
service.hooks(hooks);
};
Been stuck here for a while now. Please help.
For reference, from this issue, the answer is to use params.route and Feathers normal find(params):
module.exports = function (app) {
const Model = createModel(app);
const paginate = app.get('paginate');
const options = {
name: 'results',
Model,
paginate
};
// Initialize our service with any options it requires
app.use('/results', createService(options));
app.use('/results/:id/hr_bargraph_image', {
async find(params){
const { id } = params.route;
const results = await app.service('results').get(id);
return {
imageData: ''
};
}
});
// Get our initialized service so that we can register hooks and filters
const service = app.service('results');
service.hooks(hooks);
};

Objection.js - Query builder not a function using insert method

I'm new to nodejs Development and I currently practicing CRUD operations on my postgresql. I used Objection.js for the ORM and Model making. I follow some codes from the docs and edit necessary lines but I don't actually get it to success instead it returns this error:
builder.knex(...).queryBuilder is not a function
I am following MVC pattern so I seperate the files according to it.
My controller:
'use strict';
const Todo = require('./../models/Todo');
class TodoController {
createTodo() {
Todo
.query()
.insert({
'title': 'asdasdasda',
'description': 'sdasdasdasdasdsad',
'date': '2017-12-12',
'isActive': true,
})
.then(name => {
console.log(name.description);
})
.catch(err => {
console.log(err);
});
}
}
module.exports = TodoController;
Knex Schema:
knex.schema.createTableIfNotExists('todo', (table) => {
table.increments();
table.string('title', 255).notNullable();
table.text('description').notNullable();
table.boolean('isActive').defaultTo('false');
table.datetime('date').notNullable();
table.timestamp('createdAt').defaultTo(knex.fn.now());
})
Model:
'use strict';
const { Model } = require('objection');
class Todo extends Model {
static get tableName() {
return 'Todo';
}
}
module.exports = Todo;
server.js:
...
const KnexConfig = require('./knexfile');
const { Model } = require('objection');
...
...
Model.knex(KnexConfig.development);
Hopefully someone could guide me, I'm still newbie on nodejs
It looks like you're trying to pass the knex configuration object to Model.knex() whereas you need to pass the actual knex instance.
On server.js:
const { Model } = require('objection');
const knex = require('knex');
const KnexConfig = require('./knexfile');
Model.knex(knex(KnexConfig.development));
This error message seems to arise whenever the knex instance passed to Objection.js is not what is should be.

Property in class is undefined when used in class method

Writing a test REST api with NodeJs for learning purposes.
Currently I only have 1 route which accepts a parameter (which works fine).
I'm using an express router to route the GET request to my controller.
All of the routing is working as expected.
My ServiceController currently has a ctor function which accepts 2 parameters. Both of these parameters are passed into the ctor function by the router during instantiation.
In the ServiceController ctor I store the parameters in to fields.
The issue is, when I try to access these fields in a class method I'm getting a "TypeError: Cannot read property 'exec' of undefined".
I did write both of these values to the console to ensure that the ServiceController was receiving these values correctly (which it is).
So, i'm unsure why im getting this error when I attempt to access either "this.exec" or "this.logger" in the get method.
Router
import express from 'express';
import { exec } from 'child-process-promise';
import ServiceController from '../controllers/serviceController';
let routes = (logger) => {
const router = express.Router();
let controller = new ServiceController(exec, logger);
router.route('/status/:name')
.get(controller.get);
return router;
};
module.exports = routes;
ServiceController
export default class ServiceController {
constructor(childProcess, logger) {
this.logger = logger;
this.exec = childProcess;
}
get(req, res) {
if (!req.params.name) {
res.status(400).send('A service name was not provided');
} else {
this.exec(`sc query ${req.params.name}`).then(result => {
if (result.stderr) {
this.logger.log.warn(`stderr: ${result.stderr}`);
}
const regex = /STATE\s+:\s+\d+\s+(\w+)/;
let [, status] = result.stdout.toString().match(regex);
if (!status) {
throw new Error('Status query unsuccessful');
}
let service = {
name: req.params.name,
status: status
};
res.json(service);
return service;
}).catch(error => {
this.logger.log.error(`${error.name} ${error.message}`);
res.status(500).send('An error occurred while executing command');
});
}
}
}
It's a problem of this context. You use the get method on a context which is not your ServiceController instance.
Bind the method on your instance:
router.route('/status/:name')
.get(controller.get.bind(controller));
Or you can also define an arrow function in the ServiceController class.

Categories