I'm trying to connect to multiple databases from single connection using typeORM in javascript. There's a way doing it using typescript
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
#Entity({ database: "secondDB" })
export class User {
#PrimaryGeneratedColumn()
id: number;
#Column()
firstName: string;
#Column()
lastName: string;
}
I tried to replicate this in javascript like this:
const { EntitySchema } = require("typeorm");
const userSchema = {
name: "User",
database: "secondDB",
columns: {
id: {
primary: true,
type: "int",
generated: true
},
firstName: {
type: "text"
},
lastName: {
type: "text"
},
}
module.exports = new EntitySchema(userSchema);
This doesn't seem to switch databases, Is there an equivalent way of doing this in javascript. I'm connecting to a postgresDB
It's been a while since I worked with type-orm, but I know that a single connection with multiple databases at the time was only supported for MySQL and MsSQL databases.
In this document: https://orkhan.gitbook.io/typeorm/docs/multiple-connections.
It states that "Using multiple databases in a single connection" "this feature is supported only in mysql and mssql databases".
link to relevant github issue
Related
Nextauth with mysql persisting users.
I'm trying out this NextAuth thing to see if this is something I like. So far so good. There is one thing tho which is buggin me and that would be the user scheme. By default it returns a name, image and the last one I forgot.
I'd like to add more to this scheme and found some ways to do it by looking at google, however those I tried did not work.
One example I found is by extending the model which clearly makes sense...
The issue here is then me, I do not know what to change in the code below to make it work with my NextAuth credentials provider. As shown below, this doesnt work.
projectfolder -> models -> index.js
import User, { UserSchema } from "./User"
export default {
User: {
model: User,
schema: UserSchema
}
}
projectfolder -> models -> user.js
import Adapters from "next-auth/adapters"
// Extend the built-in models using class inheritance
export default class User extends Adapters.TypeORM.Models.User.model {
constructor(name, email, image, emailVerified, roles) {
super(name, email, image, emailVerified)
if (roles) { this.roles = roles}
}
}
export const UserSchema = {
name: "User",
target: User,
columns: {
...Adapters.TypeORM.Models.User.schema.columns,
roles: {
type: "varchar",
nullable: true
},
},
}
In my [...nextauth].js file I have my provider, in this provider i've added an profile() field with the extra fields. This did not solve the issue.
profile(profile) {
return {
name: profile.name,
email: profile.email,
role: profile.role
};
},
Please correct me if I am wrong but if I am using credentials, then I need to replace the "TypeORM" with something else, correct? How about the path for the files, are they correct?
This should clearly be quite easy but am I missing something or am I doing something wrong? I feel like there is a lack of documentation on extending the user model for mysql.
I've doubled checked that the role is being retrieved from the database and then added to the user variable shown here:
async authorize ....
const user = {
name: result.display_name,
role: result.role_name,
email: result.email
}
Although I can see the role being set in the variable with my console.log(), I still cannot access the role and that I suspect is because of the model. How would I resolve this? Thanks a lot in advance.
Any ideas?
----------------------- UPDATES ------------------------
Btw, here is my callback
callbacks: {
async signIn({ user, account, profile, email }) {
console.log("user", user);
return true;
},
},
and this is what it returns (shortened)
token: {
token: { name: 'Firstname Lastname', email: 'test#mail.com' },
user: {
name: 'Firstname Lastname',
role: 'administrator',
email: 'test#mail.com'
},
account: { type: 'credentials', provider: 'credentials' },
isNewUser: false,
iat: 1634193197,
exp: 1636785197
}
I'm new to TypeORM and I am facing the same problems as people here.
What I've done was create a separate Entity which I called users_info to store the other information and retrieve it after signing in.
It looks like this:
import { UserEntity } from './NextAuthEntities';
#Entity({ name: 'users_info' })
export class MemberEntity {
#PrimaryGeneratedColumn('increment')
id!: number;
#OneToOne(() => UserEntity)
#JoinColumn({
name: 'auth_id',
referencedColumnName: 'id',
})
auth_id!: UserEntity;
#Column({ type: 'varchar', nullable: true })
full_name!: string | null;
// etc
}
Then, I created a handshake API route to retrieve users_info if the user is signed-in.
When I added a new #Column on my custom UsersEntity, it threw me an error when I tried to login. It seems like TypeORMLegacyAdapter can't be extended or be different from the default UserEntity.
Hope it helps
Currently working on a personal website for myself and ran in to some difficulties with mongodb & mongoose when trying to delete a user.
Right now I have two Schema's show below.
UserSchema:
const userSchema = new mongoose.Schema({
username: {
type:String,
required: true,
unique: true,
},
password: String,
firstName: String,
lastName: String,
eMail: String,
status: {type:Boolean, default: true},
hobbies: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Hobby"
}
]
HobbySchema:
const hobbySchema = new mongoose.Schema({
title: String,
user: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
desc: String,
iconURL: String
});
My issue right now is that when I delete the user using the following route with nodeJS:
router.delete('/delete/:id', async (req,res) => {
await User.findOneAndDelete(req.params.id, (err, foundUser) => {
if(err){
console.log(err);
}else{
res.redirect("/logout");
}
})
});
I run into the issue that the Hobby collection still contains all hobbies that the user created. I'm looking to have them all deleted when the user wants to delete their account.I understand that Mongodb/Mongoose is a non-relation database and is unlike SQL as I'm coming from SQL. Is there any way to delete all hobbies a user created? (Just creating hobbies as a very basic example).
What is the best alternative? Just going with SQL lite and changing the database entirely?
Thanks
I am getting started with Sequelize. I am following the documentation they are providing on their website :http://docs.sequelizejs.com/manual/installation/getting-started.html
const Sequelize = require('sequelize');
const sequelize = new Sequelize('haha', 'postgres', 'postgres', {
host: 'localhost',
dialect: 'postgres',
operatorsAliases: false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
// SQLite only
storage: 'path/to/database.sqlite'
});
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
}
});
// force: true will drop the table if it already exists
User.sync({force: true}).then(() => {
// Table created
return User.create({
firstName: 'John',
lastName: 'Hancock'
});
});
Up until here, everything works perfectly. And the table "user" is correctly built and populated. (Although I do not understand Sequelize appends an "s" automatically to "user", any explanation.)
However when I add the following portion of code:
User.findAll().then(users => {
console.log(users)
})
I get this error :
Unhandled rejection SequelizeDatabaseError: relation "users" does not
exist
So my questions are:
Why does Sequelize add an "s" to user. (I know it makes sense but shouldn't the developer decide that)
What is causing that error? I followed the documentation but it still didn't work?
When you are defining your model you can add configurations, in this case the option that you must add is freezeTableName prevents the names from being plural.
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
}
}, {
// disable the modification of table names; By default, sequelize will automatically
// transform all passed model names (first parameter of define) into plural.
// if you don't want that, set the following
freezeTableName: true,
});
There is another interesting way you can avoid this. But you need to really focus on this way of implementation.
const User = sequelize.define("user", {
firstname: {
type: Sequelize.STRING
},
lastname: {
type: Sequelize.STRING
}
});
you intentionally put user here and use users in other places of coding(Assume sequelize will automatically transform all passed model names (first parameter of define) into plural) . This way of coding will simplify your code.
This problem occurs because creating a table is an asynchronous function. The problem is, the findAll() function can get executed while the table has not been created.
to solve this, you can use:
(async ()=>{
await User.sync({force: true});
// Table created
const users=await User.findAll();
console.log(users);
})();
The problem, in my case, was that the table users was not created. You can create the table manually with CREATE TABLE IF NOT EXISTS (SQL) or add the tableName = "users" in the options object:
export const User = db.define('user',
{
id: {
type: DataTypes.UUIDV4,
autoIncrement: true,
primaryKey: true,
},
name: {
type: new DataTypes.STRING(128),
allowNull: false,
},
email: {
type: new DataTypes.STRING(128),
allowNull: true,
},
password: {
type: new DataTypes.STRING(128),
allowNull: true,
},
},
{
freezeTableName: true,
tableName: "users"
}
);
Run that code twice.
Before running the second time, comment out the following code,
// force: true will drop the table if it already exists
User.sync({force: true}).then(() => {
// Table created
return User.create({
firstName: 'John',
lastName: 'Hancock'
});
});
Maybe answer is not entirely connected with you question but I want to describe my experience with this error
Error: relation "users" does not exist.
It appears Sequelize make migrations based on migrations file names and it alphabetical order. My problem was my files naming was not sorted in order to create proper connections.
If you face with this problem make sure yours migration files are fired in proper (in alphabetically) order.
The proper order is to first migrate table without connections (eg. table_A) and then tables with connections to table_A.
As I said this may not be answer for your particular order but I want to share my experiences because I didn't find this information on the internet when I was looking for this error.
Simply append tableName: "Users" to your model configuration.
The easiest way I found to solve, is to explicitly set the tableName on the model. As others have mentioned, sequelize defaults to the plural form of a model as the table name. For instance User, becomes Users.
When you query, sequelize looks after a table with the same name as your model User. By defining the tableName in the model, sequelize should search the correct table. Append tableName: "Users" to your model configuration i.e:
User.init(
{
email: DataTypes.STRING,
password: DataTypes.STRING,
role: DataTypes.INTEGER,
},
{
sequelize,
modelName: 'User',
tableName: 'Users',
}
);
If you want Sequelize to use a singular word ('info') for a model and that same singular word for the table ('info'), you can name the model 'info' and also add tablename: 'info' to the definition of your model.
This is a way to control Sequelize's default behavior of pluralizing model names, or not, on a table-by-table basis.
info.js
module.exports = (sequelize, DataTypes) => {
const info = sequelize.define('info', {
firstname: DataTypes.STRING,
email: DataTypes.STRING,
phone: DataTypes.STRING,
}, {
tableName: 'info'
});
return info;
};
I am trying to create a pagination in relay & graphql in my schema. This is my code:
const GraphQLFriendByUser = new GraphQLObjectType({
name: 'FriendByUser',
fields: {
id: globalIdField('FriendByUser'),
_id: {
type: GraphQLString,
resolve: (root) => root._id,
},
email: {
type: GraphQLBoolean,
resolve: (root) => root.email,
},
fullName: {
type: GraphQLString,
resolve: (root) => {
return root.fullName;
},
},
},
interfaces: [nodeInterface],
});
const {
connectionType: FriendsByUserConnection,
edgeType: GraphQLFriendByUserEdge,
} = connectionDefinitions({
name: 'FriendByUser',
nodeType: GraphQLFriendByUser,
});
I created this similarly looking at sample in todo-modern, In my TodoListHome component, this is my graphql query:
friendsByUserContext( first: 200 ) #connection(key: "TodoListHome_friendsByUserContext") {
id
_id
fullName
email
}
there's no problem when I update the schema, but when I try to build, this is my error:
Invariant Violation: RelayParser: Unknown field id on type
FriendByUserConnection. Source: document TodoListHome_viewer file:
C:\Users\PE60\Desktop\socialnetworking-todoapp\js\components\TodoListHome.js.
The execution doesn't even reach on resolve, so I cannot log. but I believe the error is not from there. Help?
Since you're using graphql-js, you probably have graphiql hosted on your /graphql endpoint. That's a good place to debug queries and see the structure of your schema. There you'll see that the connection you're talking about has the field edges which has the field node which has the fields you're looking for.
From sails.js example,
// Person.js
var Person = {
attributes: {
firstName: 'STRING',
lastName: 'STRING',
age: {
type: 'INTEGER',
max: 150,
required: true
}
birthDate: 'DATE',
phoneNumber: {
type: 'STRING',
defaultsTo: '111-222-3333'
}
emailAddress: {
type: 'email', // Email type will get validated by the ORM
required: true
}
}
};
Now how would I add emailAddress to have a home and office as embedded fields?
Tried to do it this way:
emailAddress: { {
work: {
type: 'email',
},
personal: {
type: 'email',
}
}
},
and
emailAddress: {
attributes: {
work: {
type: 'email',
},
personal: {
type: 'email',
}
}
},
both don't work. I get errors such as "No Rules found for attributes" for the second case, "Unexpected token { " in the first case.
Ok, Following through some threads on this.
It seems Sails Waterline has no support for embedded MongoDB schema at this stage.
You can write your own contribution or force it, but the out of box support (model validation) etc. need to be hacked too.
https://github.com/balderdashy/sails-mongo/issues/44
The other option - sails-mongoose is unfortunately not supported too.
From where can we decide collection name in use of "sails-mongoose" package, in node.js + sailsjs?
Update.
Starting with V0.10, Sails is supporting associations. Perhaps that will make it work. Still experimental.
Update.
With the associations functionality you can force a schema in different models and create references between them, but so far it doesn't seem like you'll be able to embed them - only relate them from different collections/tables.
https://github.com/balderdashy/sails-mongo/issues/44
It seems they already have it planned as a Feature Request.