Sequelize JOIN with function in conditoin - join

I googled a bit, looked into documentation but no sign for functions in join conditions
I wanna do (pls ignore the obvious issue with the db design => name_department instead of id_department.. this is just an example)
SELECT *
FROM emp e
JOIN department d
ON e.name_department = lower(d.name_department)
How do I define such relation in the Sequelize model ???
const { Sequelize } = require('sequelize')
const { db } = require('./../../db/sequelize')
const dbConfig = require('./../../config/db.config')
const Department = require('./department.model')
const Employee = db.define('emp', {
id: {
type: Sequelize.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING(255)
},
name_department: {
type: Sequelize.STRING(255)
}
}, {
schema: dbConfig.backendSchema,
freezeTableName: true,
timestamps: false,
})
Employee.hasOne(Department, {as: 'dpt', foreignKey: 'name_department', sourceKey: '????????'})
module.exports = Employee
How do I implement the function there? I simply tried -> lower(name_department) but it doesn't work ... is there any way to use functions?

It's impossible with Sequelize to indicate something other than a real field from a table/view.
One possible solution is to add a field with calculated function result and join two models using this field (Obviously it would be totally up to you to keep this field up-to-date).

Related

Return ONLY selected fields within a TypeORM find request

I'm struggling in returning only selected fields in my TypeORM find request.
Assuming the following request
const data = await AppDataSource.manager.find(User, {
select: {
id: true,
hash: true,
firstname: true,
lastname: false,
},
take: 10, // Just here to shrink dataset
});
The script works pretty well excepted that it return every field of my model, with default value initialized.
[
User {
prefix: 'usr',
hash: 'usr_835b0ad2-XXXXXX',
email: undefined,
accountValidated: false,
role: 'free',
myKeyOne: true,
myKeyTwo: false,
gender: 'unspecified',
lastConnexion: 2023-01-19T10:11:02.733Z,
pendingDeletion: false,
deletionDate: undefined,
firstname: 'Clément',
lastname: undefined,
password: undefined,
facebookId: undefined,
googleId: undefined,
id: 158
},
...
]
Of course, it's not usable as it, because I have extensive relations, and thus the payload would be extremely heavy.
Are you aware of a method / a way to remove all unnecessary fields ?
i.e. I'm expecting
[
User {
id: 124,
hash: 'urs_XXXX',
firstname: 'Clément',
},
...
]
In older versions of typeorm I think you need to select with an array of strings, try:
select: ["id", "hash", "firstname"],
See this older version of the docs: https://github.com/typeorm/typeorm/blob/bc60dd559ba42af083ddea17f01205c78c83c7e0/docs/find-options.md
After hours of researches I've finally found out why it behaved like this.
TypeORM relies on class definitions and typescript so...
if you have typescript default values OR if you have rewrite your constructor, all the "default" properties are injected.
Assuming a User model
❌ You should not do
#Entity({ name: 'users' })
class User {
#Column()
firstname?: string;
#Column({ nullable: true })
lastname?: string;
#Column({ unique: true, nullable: false })
email!: string;
#Column({ name: 'account_validated', nullable: false})
accountValidated?: boolean = false
//Your other fields...
}
✅ You should do
#Entity({ name: 'users' })
class User {
#Column()
firstname?: string;
#Column({ nullable: true })
lastname?: string;
#Column({ unique: true, nullable: false })
email!: string;
// Use default argument of the decorator
#Column({ name: 'account_validated', nullable: false, default: false})
accountValidated?: boolean
//Your other fields...
}
And if you need in some way to init a default, then create a public static method which return the Entity instead of using the constructor.
#Entity({ name: 'users' })
class User {
//...fields
public static init(...params): User {
let _user = new User()
//...populate your object
return _user
}
}

Loopback POST array of entry?

I want to insert 10 entries with one query against 10 queries.
I read that it's possible to do it by sending an array like this :
But I get this error:
Do I need to set something? I don't know what to do at all.
Repo with a sample : https://github.com/mathias22osterhagen22/loopback-array-post-sample
Edit:
people-model.ts:
import {Entity, model, property} from '#loopback/repository';
#model()
export class People extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
name: string;
constructor(data?: Partial<People>) {
super(data);
}
}
export interface PeopleRelations {
// describe navigational properties here
}
export type PeopleWithRelations = People & PeopleRelations;
The problem with your code was :
"name": "ValidationError", "message": "The People instance is not
valid. Details: 0 is not defined in the model (value: undefined);
1 is not defined in the model (value: undefined); name can't be
blank (value: undefined).",
Here in above as in your #requestBody schema, you are applying to insert a single object property, where as in your body are sending the array of [people] object.
As you can see in your people.model.ts you have declared property name to be required, so system finds for the property "name", which obviously not available in the given array of object as primary node.
As you are passing index array, so its obvious error that you don't have any property named 0 or 1, so it throws error.
The below is the code hat you should apply to get insert the multiple, items of the type.
#post('/peoples', {
responses: {
'200': {
description: 'People model instance',
content: {
'application/json': {
schema: getModelSchemaRef(People)
}
},
},
},
})
async create(
#requestBody({
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(People, {
title: 'NewPeople',
exclude: ['id'],
}),
}
},
},
})
people: [Omit<People, 'id'>]
): Promise<{}> {
people.forEach(item => this.peopleRepository.create(item))
return people;
}
You can also use this below
Promise<People[]> {
return await this.peopleRepository.createAll(people)
}
You can pass the array of your people model by modifying the request body.If you need more help you can leave comment.
I think you have a clear solution now. "Happy Loopbacking :)"

Sequelize.s include where ancestor column

Sorry for my bad English, but I do not know how to better formulate the title.
Anyway I have the following 3 models
const ModelAlpha = sequelize.define('tbl_A', {
id: {
type: Sequelize.INTEGER.UNSIGNED,
field: 'a_id',
autoIncrement: true,
primaryKey: true,
}
});
const ModelBeta = sequelize.define('tbl_B', {
id: {
type: Sequelize.INTEGER.UNSIGNED,
field: 'b_id',
autoIncrement: true,
primaryKey: true,
},
attributeB: {
type: Sequelize.TINYINT.UNSIGNED,
field: 'b_attribute'
}
});
const ModelCharlie = sequelize.define('tbl_C', {
id: {
type: Sequelize.INTEGER.UNSIGNED,
field: 'c_id',
autoIncrement: true,
primaryKey: true,
},
attributeC: {
type: Sequelize.TINYINT.UNSIGNED,
field: 'c_attribute'
}
});
One ModelAlpha has one ModelBeta.
ModelAlpha has a foreign key column referencing the primary key of ModelBeta.
ModelAlpha can have many ModelCharlie
I am to trying to achieve the following
SELECT C.* FROM tbl_C
JOIN tbl_A ON tbl_A.a_id = C.fkey_a_id
JOIN tbl_B ON tbl_B.b_id = tbl_A.fkey_b_id
WHERE C.c_attribute = B.b_attribute
AND tbl_A.a_id = 123
So, in other words, all Charlies of the Alpha whose id is 123
and whose c_attribute is equal to b_attribute of the Beta
So far I have written something like the following,
but I am stuck as to what I am supposed to add to the where
clause.
ModelAlpha.belongsTo(ModelBeta, {foreignKey: 'fkey_b_id', as: 'beta'});
ModelAlpha.hasMany(ModelCharlie,{foreignKey: 'fkey_a_id', as : 'charlies'});
ModelAlpha.find({
where: {id: '123'},
include: [
{
model: ModelBeta,
as: 'beta',
attributes: [],
},
{
model: ModelCharlie,
as: 'charlies',
attributes:[],
where: {
attributeC: ......
}
}
],
limit: 1
}).then(result => {
//...
});
Has anyone come up with this situation before?
Thank you.

Mongodb and Node js

i am new in node js, and I am trying to build an app quiz engine using node js and mongo DB. I am not sure what I need to make a schema for quiz engine. So anyone can help me.
Here is an example of a User Schema...
var userSchema = new Schema({
name: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
}
});
But like the comment stated, you will have to be more specific.
As far as i can guess, a quiz will be given by user and it will have questions. So, you can make two entities :
i) User entity
ii) Quiz/Questions entity
User entity schema :
module.exports = {
attributes = {
name: {
type: String,
required: true
},
password: {
type: String,
required: true
}
password: {
type: String,
required: true
}
}
};
Question entity schema :
module.exports = {
attributes = {
questionLabel: {
type: 'String',
required: true
},
choices: {
type: 'Array',
required: true
}
};
Hello this is my schema
enter code here var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var img_schema = new Schema({
title:{type:String,require:true},
creator:{type:Schema.Types.ObjectId, ref: "User" },
extension:{type:String,require:true},
foto:{type:String,require:true},
uso:{type:String,require:true}
});
var Imagen = mongoose.model("Imagen",img_schema);
module.exports = Imagen;
This is the example of user schema. you can replace with your requirement.
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
profileimage:{
type: String
}
});
var User = module.exports = mongoose.model('User', UserSchema);
I will suggest you to use mongoose to define your mongoDB collection schemas. Mongoose facilitates a lot of processes between nodejs and mongoDB.
You can install mongoose using following command:
npm i mongoose
Then create a schema like this:
import mongoose from 'mongoose';
const { Schema } = mongoose; //Pulling schema out of mongoose object
const QuizEngineSchema = new Schema({
name: String,
phoneNumber: Number,
// other data that you need to save in your model
},
{timestamps: true},
{id: false});
//Plugging the Schema into the model
const QuizEngine = mongoose.Model('QuizEngine',QuizEngineSchema);
export default QuizEngine;
Hope this helps!

Propel archivable behavior doesn't work properly (archived_at column doesn't get updated on insert)

I have some problems with the Propel's archivable behavior. For some reasons, Propel doesn't set archived_at field to the current datetime when the object is being archived.
My schema:
SeminarCustomer:
tableName: seminar_customer
columns:
id: { type: integer, required: true, primaryKey: true, foreignClass: Customer, foreignReference: id, onDelete: cascade }
...
office_id: { type: integer, required: false, foreignTable: office, foreignReference: id }
entity_id: { type: integer, required: true, default: 1 }
propel_behaviors:
timestampable: ~
archivable: ~
SeminarCustomer::archive method:
public function archive(PropelPDO $con = null)
{
if ($this->isNew()) {
throw new PropelException('New objects cannot be archived. You must save the current object before calling archive().');
}
if (!$archive = $this->getArchive($con)) {
$archive = new SeminarCustomerArchive();
$archive->setPrimaryKey($this->getPrimaryKey());
}
$this->copyInto($archive, $deepCopy = false, $makeNew = false);
// NOTE: here should be $archive->setArchivedAt(time());
$archive->save($con);
return $archive;
}
archived_at column definitely exists in my seminar_customer_archive table.
Does anybody know what I am doing wrong ? Or maybe there is an error in the schema?
Symfony: 1.4.17-DEV
Propel: 1.6.3
Thanks in advance!
can you force the log_archived_at parameter of the Archivable behavior? It should work out of the box...
If it can helps, here is the documentation: http://www.propelorm.org/behaviors/archivable.html
EDIT: Fixed by PR #310

Resources