How to create a one-to-one relationship using sequelize and mysql? - javascript

I am trying to create a one-to-one relationship between two entities. I am using sequelize as ORM to the database mysql.
My model definitions are the following:
var user = (sequelize, DataTypes) => {
const User = sequelize.define('user', {
name: {type: DataTypes.STRING, allowNull: false, unique: true }
}, {
timestamps: false
});
return User;
};
var product = (sequelize, DataTypes) => {
const Product = sequelize.define('product', {
title: {type: DataTypes.STRING, allowNull: false, unique: true, default: 'Coop Default' }
}, {
timestamps: false
});
return Product;
};
and one-to-one relation is made with the following lines of code
db.product.belongsTo(db.user);
db.user.hasOne(db.product);
But, this does not create a unique foreign key in the table products.
mysql> desc products;
+--------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | UNI | NULL | |
| userId | int(11) | YES | MUL | NULL | |
+--------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
What else should I do in the ORM to ensure userId is unique?

I am able to force the unique constraint on the foreignKey by mentioning it in the model definition, apparently, sequelize is not able to do that from the associations.
var product = (sequelize, DataTypes) => {
const Product = sequelize.define('product', {
title: { type: DataTypes.STRING,
allowNull: false,
unique: true
},
userId: { type: DataTypes.INTEGER,
allowNull: false,
unique: true
}
}, {
timestamps: false
});
return Product;
};

Related

How do I fix the Typescript error Unable to compile TypeScript:

I have not been able to figure out the reason for the error I am getting. I'm not a Typescript ninja so maybe the error is obvious to someone here. My project is running micro services using Kubernetes and one of the services is throwing the following error when I run the project.
I have Googled as much as seems possible and found nothing helpful. The error is very specific to some attempts to make mongoose play nicely.
Thanks in advance.
My model file:
import mongoose from 'mongoose';
import { Order, OrderStatus } from './order';
interface TicketAttrs {
id: string;
price: number;
title: string;
}
export interface TicketDoc extends mongoose.Document {
id: string;
title: string;
price: number;
isReserved(): Promise<boolean>;
}
interface TicketModel extends mongoose.Model<TicketDoc> {
build(attrs: TicketAttrs): TicketDoc;
}
const schema = new mongoose.Schema({
title: {
type: String,
required: true
},
price: {
type: Number,
required: true,
min: 0
}
}, {
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
}
}
});
schema.statics.build = (attrs: TicketAttrs) => {
return new Ticket({
_id: attrs.id,
price: attrs.price,
title: attrs.title
});
};
/**
* Queries the orders to determine if a ticket is currently
* reserved.
*
* #returns boolean
*/
schema.methods.isReserved = async function() {
const existingOrder = await Order.findOne({
ticket: this,
status: {
$in: [
OrderStatus.Created,
OrderStatus.AwaitingPayment,
OrderStatus.Complete
]
}
});
return !!existingOrder;
};
const Ticket = mongoose.model<TicketDoc, TicketModel>('Ticket', schema);
export { Ticket };
The Error:
[orders] Compilation error in /app/src/models/ticket.ts
[orders] [ERROR] 11:43:04 тип Unable to compile TypeScript:
[orders] src/models/ticket.ts(57,5): error TS2322: Type 'Document<any, {}>' is not assignable to type 'Pick<_LeanDocument, "id" | "_id" | "__v" | "title" | "price" | "isReserved"> | QuerySelector<Pick<_LeanDocument, "id" | ... 4 more ... | "isReserved">> | undefined'.
[orders] Type 'Document<any, {}>' is missing the following properties from type 'Pick<_LeanDocument, "id" | "_id" | "__v" | "title" | "price" | "isReserved">': title, price, isReserved
[orders]
Schema is a generic constructor, so try this:
new mongoose.Schema<TicketDoc>({...})
I brought the idea from here out.

Prisma: filtering and count in 1-N relationship

model DataProvider {
id Int
name String
applications Application[]
##map("data_providers")
}
model Application {
id Int
name String
data_provider_id Int
running Boolean
data_providers DataProvider
##map("applications")
}
I want to get for each dataProvider how many applications with running = true there are.
DataProvider Application
----------------- -----------------------------------------------
id | name id | name | data_provider_id | running
----------------- -----------------------------------------------
1 | dp1 2 | app2 | 1 | true
-----------------------------------------------
3 | app3 | 1 | false
accordingly to achieve this result
dataProvider = {id: 1, name: 'dp1', _count: {applications: 1}}
I tried with query
this.prisma.dataProvider.findMany({
include: {
_count: {
select: {
applications: true
}
}
},
where: {
applications: {
some: {
running: {
equals: true
}
}
}
},
})
I guess I always get {applications: 2} as a result 2 to some, but I can use only some, every and none. What am I wrong?

Typescript different interface depending on function argument

I have following scenario, i have 2 interfaces:
export interface UserInterface extends Document {
email: string,
role: string,
created: Date,
disabled: Boolean,
author: AuthorInterface
}
export interface UserModelInterface extends UserInterface {
password: string
}
and i have one method:
public findUserById(_id: mongoose.Types.ObjectId | string, sensitive: Boolean = false): Promise<UserInterface | null> {
if (sensitive) return User.findOne({ _id }).exec()
return User.findOne({ _id }, { password: 0 }).exec()
}
I want following:
This is an method that gets an user by ID.
sensitive is by default at false witch leads that the password is exluded so i use UserInterface
Problem i have now is if somebody sets sensitive on true then i would need to use UserModelInterface and not UserInterface because password is excluded in UserInterface
Is this possible?
Thank you #Bergi for showing me the direction. The solution is to use overloads:
public findUserById(_id: mongoose.Types.ObjectId | string, sensitive?: false): Promise<UserInterface | null>
public findUserById(_id: mongoose.Types.ObjectId | string, sensitive?: true): Promise<UserModelInterface | null>
public findUserById(_id: mongoose.Types.ObjectId | string, sensitive: Boolean = false): Promise<UserModelInterface | UserInterface | null> {
if (sensitive) return User.findOne({ _id }).exec()
return User.findOne({ _id }, { password: 0 }).exec()
}

Unknown column 'created_at' in 'field list

Here is my customer_schema.js file:
up () {
this.create('customers', (table) => {
table.increments()
table.string('name', 30)
})
}
CustomerSeed.js:
class CustomerSeeder {
async run () {
const customer = await Factory
.model('App/Models/Customer')
.create()
console.log('customer: ')
}
}
The Customer.js model is "empty "
I run the migrations, all is Ok, but can not run the seeds : adonis seed throws this error message:
code: 'ER_BAD_FIELD_ERROR',
errno: 1054,
sqlMessage: "Unknown column 'created_at' in 'field list'",
sqlState: '42S22',
index: 0,
sql:
"insert into `customers` (`created_at`, `name`, `updated_at`) values ('2019-03-04 20:01:17', 'Peter Walsh', '2019-03-04 20:01:17')" }
Why this happens? I did not even declare table.timestamps() in my schema file and :
describe customers;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
Edit:
static get createdAtColumn () {
return null;
}
static get updatedAtColumn () {
return null;
}
Add this 2 functions to your model, it should work :)
To add to the previous good answer, when you have lot of models as the application grows, you can automate the above solution instead of writing it as per model:
'use strict'
class NoTimestamp {
register (Model) {
Object.defineProperties(Model, {
createdAtColumn: {
get: () => null,
},
updatedAtColumn: {
get: () => null,
},
})
}
}
module.exports = NoTimestamp
Credit to Romain Lanz who showed me this solution.

ER_BAD_FIELD_ERROR when using Waterline ORM in Sails.js

I'm getting the following error when trying to call .create() on a model from a Sails.js controller.
Here is my model, TemperatureReading.js:
module.exports = {
connection: 'mainDatabase',
tableName: 'TemperatureReading',
attributes: {
id: {
columnName: 'id',
type: 'integer',
minLength: 1,
primaryKey: true,
unique: true
},
deviceId: {
columnName: 'deviceId',
type: 'integer',
minLength: 1,
},
temperatureReading: {
columnName: 'temperatureReading',
type: 'string',
max: 150,
required: true
},
dateRecorded: {
columnName: 'dateRecorded',
type: 'string',
},
}
};
routes.js:
module.exports.routes = {
'get /enterSensorReading': 'MainController.getSensorReading'
};
MainController.getSensorReading:
getSensorReading: function (request, response) {
var temperatureReading = request.param('temperatureReading');
var date = new Date();
var dateRecorded = date.getDate() + "/"
+ (date.getMonth()+1) + "/"
+ date.getFullYear() + " "
+ date.getHours() + ":"
+ date.getMinutes() + ":"
+ date.getSeconds();
console.log(temperatureReading);
TemperatureReading.create({temperatureReading: temperatureReading, dateRecorded: dateRecorded}).exec(function(err, createdReading) {
if(err) {
response.send(err);
} else {
console.log('Created reading');
}
});
}
connections.js
module.exports.connections = {
mainDatabase: {
adapter: 'sails-mysql',
host: '127.0.0.1',
port: 3306,
user: 'myUser',
password: 'myPW',
database: 'MAIN'
}
};
And finally, my database structure:
TemperatureReading
------------------
id int(5) PK
deviceId int(5)
temperatureReading varchar(255)
date varchar(255)
Any ideas as to what is going wrong?
The database structure should be something like this:
mysql> describe TemperatureReading;
+--------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| deviceId | int(11) | YES | | NULL | |
| temperatureReading | varchar(255) | YES | | NULL | |
| dateRecorded | varchar(255) | YES | | NULL | |
| createdAt | datetime | YES | | NULL | |
| updatedAt | datetime | YES | | NULL | |
+--------------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
It should be dateRecorded and not just date
If its a new app and you are creating the table from scratch, use add "migrate": "drop" in your model. This will automatically create the table for you. Make sure to remove this line next time you lift the server. If this does not solve the problem, then I don't see any issue with the code. I tested and it worked perfectly on my system. It might be possible that something messed up with your sails-mysql adapter. If fixing your database structure does not solve the problem, try this
npm uninstall sails-mysql
npm cache clear
npm install sails-mysql
Even more rigorous way would be:
rm -Rf node_modules
npm cache clear
npm install
Let me know if this solves the problem you are facing

Categories

Resources