I'm working on a backend that is utilizing Node and Sequelize ORM. The database being used is PostgreSQL. I've used hasOne() in the code before and it worked great all the createAssociation(), getAssociation() methods from the hasOne() relationship worked when I used it before. However for some reason it is giving me a problem now.
index.js
const Connection = new Sequelize(
'postgres',
'postgres',
null,
{
dialect: 'postgres',
host: '192.168.99.100',
port: '5432',
}
);
const ModelSeven = Connection.define('modelSeven', ModelSevenSchema),
ModelFive = Connection.define('modelFive', ModelFiveSchema),
ModelOne = Connection.define('modelOne', ModelOneSchema),
ModelSix = Connection.define('modelSix', ModelSixSchema),
ModelThree = Connection.define('modelThree', ModelThreeSchema),
ModelFour = Connection.define('modelFour', ModelFourSchema),
ModelOne.hasOne(ModelThree); // Defines hasOne() relationship
ModelOne.hasOne(ModelFour); // Defines hasOne() relationship
ModelSix.belongsToMany(ModelOne, {through: 'Pivot'});
ModelOne.belongsToMany(ModelSix, {through: 'Pivot' });
ModelOne.belongsTo(ModelSeven);
ModelThree.hasMany(ModelFive);
ModelFour.hasMany(ModelFive);
export default Connection;
utilize.js
import DB from './somePathToIndex.js';
//GraphQL resolve function
async resolve (root, args, context) {
//creates ModelOne
var ModelOne = await DB.models.ModelOne.create({
value: args.value,
valueTwo: args.valueTwo
});
// attempts to createModelThree/createModelFour from hasOne() relationship
var ModelThree = await ModelOne.createModelThree({});
var ModelFour = await ModelOne.createModelFour({});
// Maps through value array finding the modelFive with and id and adding
// it to modelThree via hasMany() relationship
args.value.map(async (id, key) => {
var ModelFive = await DB.models.ModelFive.findAll({
where: {
id: id
}
});
await ModelThree.addModelFive(ModelFive);
});
// Maps through value array finding the modelFive with and id and adding
// it to modelFour via hasMany() relationship
args.valueTwo.map(async (id, key) => {
var ModelFive = await DB.models.ModelFive.findAll({
where: {
id: id
}
});
await ModelFour.addModelFive(ModelFive);
});
return ModelOne;
}
The problem is that when node hits the line:
var ModelThree = await ModelOne.createModelThree({});
var ModelFour = await ModelOne.createModelFour({});
Gives me the following error:
"errors": [
{
"message": "ModelOne.createModelThree is not a function",
"locations": [
{
"line": 38,
"column": 3
}
]
}
]
This error is saying that the hasOne() relationship method create[Association]() is not a function. I cannot really tell why this is. If you know why please let me know.
Related
Good evening.
I'm building an Express REST API using SQLite, with Sequelize being my ORM of choice.
I was working with an existing database, so I used a package called sequelize-auto in order
to generate my models.
Problem is, Sequelize for some reason won't see my database, a .db file, or won't detect the table, despite being clearly defined. The problem occurs in this block of code:
const Sequelize = require('sequelize');
const sequelize = new Sequelize('expenserdb', 'user', 'pass', {
dialect: 'sqlite',
host: '../database/expenserdb.db'
});
const initModels = require('../models/init-models');
const models = initModels(sequelize);
module.exports = class dbService {
editUserName(newName) {
models.User.update({Name: newName}, {
where: {
UserId: 1
}
})
.catch((err) => {console.log(err)});
}
}
This is my dbService.js file, and as you can see, the database is clearly defined, with the name, location and everything being correct. Despite all of this, I'm still getting:
Error: SQLITE_ERROR: no such table: User {errno: 1, code: 'SQLITE_ERROR', sql: 'UPDATE `User` SET `Name`=$1 WHERE `UserId` = $2'
This service is being injected into my controller via awilix, and the method is called inside the controller:
const container = require("../containerConfig");
const dbService = container.resolve("dbService");
exports.runNameChange = async (req) => {
const newName = JSON.stringify(req.body.name);
const result = await dbService.editUserName(newName);
return result;
};
And in turn, the controller method is ran when this endpoint is hit:
app.post('/updateuser', async function(req, res) {
const result = await userController.runNameChange(req);
res.status(200).send(String(result));
});
Also, the dboptions.json file:
{
"storage":"./database/expenserdb.db"
}
I'm new to Node, Express, and Sequelize in general. I might have missed something crucial, but I can't seem to realize what. Help is greatly appreciated.
Update: just figured it out, you need the FULL path and not the relative path in the
verbose constructor, as such:
const sequelize = new Sequelize('expenserdb', 'user', 'pass', {
dialect: 'sqlite',
storage: 'E:/desktopshortcuts/yahalom/expenser/expenser-server/database/expenserdb.db'
});
I am writing mongodb aggreagation query in nodejs. I tried my best to figure it out, but the codes won't work in my method. I'm getting following error:TypeError: client.db is not a function
const { MongoClient, ObjectId } = require('mongodb');
async function main(){
const uri = `mongodb://${dbUser}:${dbPassword}#${ipAddress}:${port}/${dbName}`;
const client = new MongoClient(uri);
try {
await client.connect();
await printStudents("541516516165164489d3aee");
} finally {
await client.close();
}
}
main().catch(console.error);
/**
* Print the students for a given schoolId
* #param {MongoClient} client A MongoClient that is connected to a cluster with the education database
* #param {ObjectId} schoolId
*/
async function printStudents(client,schoolId){
const pipeline = [
{
'$match' : { '_id' : ObjectId(schoolId) }
},
{
'$project':
{
'_id': { '$toString': '$_id'}
}
},
{
'$lookup':
{
'from': 'students',
'localField': '_id',
'foreignField': 'schools',
'as': 'Students'
}
}
];
const aggCursor = client.db("education").collection("schools").aggregate(pipeline);
await aggCursor.forEach( err => {
console.log(`${err._id}: ${err.$lookup}`);
});
}
I hope I get some good advice on how to tackle the problem properly. :)
You're passing a string as the first argument, which should be the mongo db client.
Change from :
await printStudents("541516516165164489d3aee");
to :
await printStudents(client,"541516516165164489d3aee");
When calling the printStudents method, you have not passed the client object as a parameter. By calling printStudents("541516516165164489d3aee"), the client parameter is a string and the schoolId parameter is undefined.
You should call printStudents(client, "541516516165164489d3aee") instead.
I want to sum a column in a Bookshelfjs relationship. I have my query set up as
return this.hasMany('MutualFundPortfolio').query().sum('balance');
But I am having this error TypeError: Cannot read property 'parentFk' of undefined any body has any clue how solve this? It seems Bookshelf doesn't support sum
const moment = require('moment');
const Bookshelf = require('../bookshelf');
require('./wishlist');
require('./kyc');
require('./wallet');
const User = Bookshelf.Model.extend({
tableName: 'users',
hasTimestamps: true,
hidden: ['code', 'password'],
toJSON(...args) {
const attrs = Bookshelf.Model.prototype.toJSON.apply(this, args);
attrs.created_at = moment(this.get('created_at')).add(1, 'hour').format('YYYY-MM-DD HH:mm:ss');
attrs.updated_at = moment(this.get('updated_at')).add(1, 'hour').format('YYYY-MM-DD HH:mm:ss');
return attrs;
},
local_wallet() {
return this.hasMany('LocalWallet').query((qb) => {
qb.orderBy('id', 'DESC').limit(1);
});
},
mutual_fund_portfolio() {
return this.hasMany('MutualFundPortfolio').query().sum('balance');
},
global_wallet() {
return this.hasMany('GlobalWallet').query((qb) => {
qb.orderBy('id', 'DESC').limit(1);
});
},
local_gift_card_wallet() {
return this.hasMany('LocalGiftCardWallet').query((qb) => {
qb.orderBy('id', 'DESC').limit(1);
});
},
global_gift_card_wallet() {
return this.hasMany('GlobalGiftCardWallet').query((qb) => {
qb.orderBy('id', 'DESC').limit(1);
});
}
});
module.exports = Bookshelf.model('User', User);
Above is the full user model. I am then getting the value as
return User.where({ id })
.orderBy('id', 'DESC')
.fetch({
withRelated: [
'mutual_fund_portfolio',
'local_wallet',
'global_wallet',
'local_gift_card_wallet',
'global_gift_card_wallet'
]
})
The mutual_fund_portfolio comes out as an empty array.
hasMany performs a simple SQL join on a key. I believe the TypeError: Cannot read property 'parentFk' of undefined error refers to the fact that the table you are referencing here MutualFundPortfolio does not share a key with the table in the model you are using here.
It's not visible above sample but I'm assuming it's something like:
const User = bookshelf.model('User', {
tableName: 'users',
books() {
return this.hasMany('MutualFundPortfolio').query().sum('balance');
}
})
In my hypothetical example the users table has a primary key id column userId that is also in MutualFundPortfolio as a foreign key. My guess is that the error is because MutualFundPortfolio does not have that column/foreign key.
I was hoping to get some help. I just started using Postgres with my Node applications and am curious to find out how to go about dealing with models and model methods. What is the best practice when working with Node and Postgres in regards to models and methods? I was looking around and all I could find is something called Objection, but is it absolutely necessary I take that route?
Ideally I would like to have a model.js file for each component but I have not seen them used when dealing with Postgres + Node.
Any help is greatly appreciated. Thanks guys, hope you all had a great Thanksgiving!
Assuming that viewer can understand basic javascript modules and that the codes are mostly self explanatory
This is my model.js file
module.exports = ({
knex = require('./connection'),
name = '',
tableName = '',
selectableProps = [],
timeout = 1000
}) => {
const query = knex.from(tableName)
const create = props => {
delete props.id
return knex.insert(props)
.returning(selectableProps)
.into(tableName)
.timeout(timeout)
}
const findAll = () => {
return knex.select(selectableProps)
.from(tableName)
.timeout(timeout)
}
const find = filters => {
return knex.select(selectableProps)
.from(tableName)
.where(filters)
.timeout(timeout)
}
const update = (id, props) => {
delete props.id
return knex.update(props)
.from(tableName)
.where({
id
})
.returning(selectableProps)
.timeout(timeout)
}
const destroy = id => {
return knex.del()
.from(tableName)
.where({
id
})
.timeout(timeout)
}
return {
query,
name,
tableName,
selectableProps,
timeout,
create,
findAll,
find,
update,
destroy
}
}
This is my controller.js file
const model = require('./model');
const user = model({
name: "users",
tableName: "tbl_users",
});
const getAllUsers = async (req, res, next)=>{
let result = await user.findAll();
res.send(result);
}
module.exports = { getAllUsers }
And Lastly a the connection.js file
const knex = require('knex')({
client: 'pg',
connection: {
host: 'YOUR_HOST_ADDR',
user: 'YOUR_USERNAME',
password: 'YOUR_PASS',
database: 'YOUR_DB_NAME'
},
pool: {
min: 0,
max: 7
}
});
module.exports = knex;
How can I get the number of rows (without any filter)?
I've tried this User.fetch().count() and User.count(), but I get these errors respectively:
TypeError: User.fetch is not a function
AssertionError: expected { Object (_bitField, _fulfillmentHandler0, ...) } to equal 0
Here's my model:
let bookshelf = require('../config/database');
require('./role');
var User = bookshelf.Model.extend({
tableName: 'users',
role: function() {
return this.hasOne(Role);
}
});
module.exports = bookshelf.model('User', User);
try this:
const knex = require("knex")(require("./knexfile").development);
const Bookshelf = require("bookshelf")(knex);
const User = Bookshelf.Model.extend({
tableName: "user",
idAttribute: "userid"
});
knex.migrate.latest().then(_ => {
User.forge().count().then(ret => {
console.log(ret);
process.exit(0);
});
});
the output should be:
[sombriks#sephiroth sample-knex-bookshelf]$ node index.js
Knex:warning - sqlite does not support inserting default values. Set the `useNullAsDefault` flag to hide this warning. (see docs http://knexjs
.org/#Builder-insert).
3
[sombriks#sephiroth sample-knex-bookshelf]$
please take a look at this repo if you want a more detailed info.