Using Sequelize, we normally connect two tables together such as the following:
Order.belongsTo(OrderType, {
foreignKey: {
name: 'typeId',
},
constraints: false
});
OrderType.hasMany(Order, {
foreignKey: {
name: 'typeId',
},
constraints: false
});
However, we we need to pull in info from the Contact table with two keys rather than one. We need to identify via the user + phone, not the Contact table record id. This is what we have so far, but it is not working:
Order.belongsTo(Contact, {
as: 'phoneInfo',
foreignKey: {
name: 'userId',
name: 'phone1',
},
constraints: false
});
Contact.hasMany(Order, {
foreignKey: {
name: 'userId',
name: 'phone1',
},
constraints: false
});
We have also tried adding "sourceKey" and "targetKey":
Order.belongsTo(Contact, {
as: 'phoneInfo',
foreignKey: ['userId','phone1'],
sourceKey: ['userId','phone'],
constraints: false
});
Contact.hasMany(Order, {
foreignKey: ['userId','phone1'],
targetKey: ['userId','phone'],
constraints: false
});
userId = a column in both Order & Contact tables
phone1 = a column in Order table, type string
phone = a column in Contact table, type string
The error we are getting is:
DatabaseError [SequelizeDatabaseError]: operator does not exist:
character varying = integer
I believe that this means that it is looking for the keys to be integers instead of strings. However, that is how they are in the database - strings, and need to remain so.
Is there no way to join two tables via two non-primary keys, and for those two keys to be non-integer (i.e. strings)? The best I've found is Sequelize - Join with multiple column, but there's got to be an easier way to do this in Sequelize.
Related
I have ActiveRecord models Parent and Kid. Parents have many Kids.
I have a Parent whose name is Dad, with 3 Kids, whose names are Abel, Bobby, and Cain. I want to find the Parent based on the name of only 1 of the Kids.
parent = Parent.includes(:kids).
find_by(kids: { name: 'Bobby' })
The above query provides me the Parent I want, but parent.kids only includes Bobby. I want Abel and Cain to be included in parent.kids as well, just like if I did:
Parent.find_by(name: 'Dad').kids
I could do:
Parent.includes(:kids).
find_by(kids: { name: 'Bobby' }).
tap { |parent| parent&.kids.reload }
But is there not a “better” way of fetching the rest of the kids? For instance, is there a way I could load all the kids of the parent while querying for the parent (via one SQL statement)?
How about making the Parent.includes(:kids).find_by(kids: { name: 'Bobby' } a subquery
Parent.includes(:kids).where(id: Parent.includes(:kids).find_by(kids: { name: 'Bobby' })
You want an INNER JOIN:
parents = Parent.joins(:kids).where(kids: { name: 'Bobby' })
This will only include rows from parents with a match in the kids table. You can apply it as a subquery to avoid removing the rest of the joined rows:
parents = Parent.where(
id: Parent.joins(:kids).where(kids: { name: 'Bobby' })
).includes(:kids)
I have two domain classes and the relationship between them is 1 to Many. I know how to map the columns of each class to their respective tables individually but how do I map the relationship that exists in my MSSQL database? There is no join table and I only have read-only access. I've looked at various pages of the Grails documentation and this is where I am at at the moment (One student has many courses). In my tables the foreign key that ties the two tables together is in the Courses table.
class StudentHeader { //on the one side
String stuNo
String stuName
String stuStreet
static mappedBy = [refs: "fkCustNo"]
static hasMany = [refs: CourseHeader]
static constraints = {
}
static mapping = {
table name: "[tbl_Students]", schema: "[dbo]", catalog: "[CRD].[CourseTrak]"
version false
id generator: 'assigned', name: 'stuNo'
stuNo column: '[PK_StudentNo]'
stuName column: '[Student_Name]'
stuStreet column: '[Student_Street]'
}
}
class CourseHeader { //on the many side
String courId
String courName
StudentHeader fkCourNo
static constraints = {
}
static mapping = {
table name: "[tbl_Courses]", schema: "[dbo]", catalog: "[CRD].[CourseTrak]"
version false
id generator: 'assigned', name: 'courId'
courId column: '[PK_CourseId]'
courName column: '[Course_Name]'
fkCourNo column: '[FK_CourseNo]'
}
}
As a test here is how I am trying to access the courses of a student
StudentHeader.first().refs
I believe I have it figured out. For the domain class on the many side you need to set insert and updateable equal to false like so (The object field in your "many" domain has to have the same value as the key-value pair in mappedBy):
class StudentHeader{
static mappedBy = [refs: "fkCustNo"]
}
class CourseHeader { //on the many side
String courId
String courName
StudentHeader fkCustNo
static constraints = {
}
static mapping = {
table name: "[tbl_Courses]", schema: "[dbo]", catalog: "[CRD].[CourseTrak]"
version false
id generator: 'assigned', name: 'courId'
courId column: '[PK_CourseId]'
courName column: '[Course_Name]'
fkCustNo column: '[FK_CourseNo]', insertable: false, updateable: false
}
}
mariadb,
show tables;
Board
Comment
my code,
models.Board.findAll({
attributes: [
'_no', 'title', 'content', 'createdAt'
],
include: [
{
model: models.Comment,
tableAlias: 'Comment',
attributes: [
[models.sequelize.fn('count', models.sequelize.col('_no')), 'comment']
]
}
],
group: ['_no', 'title', 'content', 'createdAt'],
order: [
['createdAt', 'DESC']
],
raw: true
}).then(function(boards)
{
res.send(JSON.stringify(boards));
});
Why error occurs?
Unhandled rejection SequelizeDatabaseError: ER_NON_UNIQ_ERROR: Column '_no' in field list is ambiguous
models.sequelize.col('_no') -> models.sequelize.col('models.Comment._no')
error, too.
models.sequelize.col ( '_ no') in the _no want to use Comment table.
thanks.
Appearently both Board and Comment have a _no column? In that case you need to specify which one you want to count, fx: models.sequelize.col('board._no')) (make sure the table name matches the pluralization and capitalization of the table in the rest of the query)
if multiple table is there in query then you need to specify which table createdAt you want to group by because node have all table createdAt(default created)
group: ["your_table_name_here\".\"createdAt"]
if we use multiple model for get record in that case same field name in 2 or more model then you need to specify which model record you want to group by so in that case i write group: ["your_table_name_here"."createdAt"]
Try to specify the model where createdAt is located
import { Parking } from "../database/models";
const parking = await Parking.findAndCountAll({
where: {
"$Parking.createdAt$": {
[Op.between]: [new Date(startDate), new Date(endDate)]
}
}
})
Im working on a user registration form that involves 3 different objects, The user, member profile, and member organization. Im trying to embed all these into a single registration form like User > Member > School. The basic implementation of this works just fine with the typical sfDoctrineForm::embedRealtion procedure.
The problem is the organization has a unique index on its member_number, the only time the the supplied value for this wont be in the database is when that user is first person to sign up from their organization. So in this case we will get a vlaidation error (or a key constraint violation if we turn the validation off).
What I want to happen instead, is that i check for the existence of the MemberOrganization with the same member_number in the database (either in a pre/post validator or in updateObject or wherever is appropriate). If it the member number already exists then i want to relate the new MemberProfile to this existing organization instead of linking it to the new one that was submitted, throwing out all the new values for that organization.
Ive tried modifying the object in the organization form via validation but this always results in a organization_id constraint violation coming from the profile:
$object = $this->getObject();
$table = $object->getTable();
$existing = $table->findOneByMemberNumber($values['member_number']);
if($existing)
{
$members = clone $object->Members;
$object->assignIdentifier($existing->identifier());
$object->fromArray($existing->toArray(false), false);
foreach($members as $member)
{
$member->link($object);
}
$values = $object->toArray(false); // return only the direct values
}
return $values;
The schema looks something like this:
User:
columns:
username: {type: string(100)}
email: {type: string(255), unique: true}
MemberProfile:
columns:
# some none authentication related user details
organization_id: {type: integer, notull: true}
user_id: {type: integer, notnull: true}
relations:
User:
local: user_id
type: one
foreign: id
foreignType: one
MemberOrganization:
local: orgainization_id
type: one
foreign: id
foreignType: many
foreignAlias: Members
MemberOrganization:
columns:
membership_number: {type: string(255), unique: true}
# other organization data
So what i ended up doing was overriding bind on the top level form (the one for the User). In this method i check for the existence of the Orgainization and if it exists i attach it to the Member Profile object and then re-embed all the subforms.
Ideally i would actually do this in the Member form but since the values are only bound at the top level form and then just cascade through the error schema for validation this seems to be a no go. Complete re-embedding seems to be required to get the object associations correct.
Some sample code (less some sanitizing code on the member number before issuing the query):
public function linkOrganizationIfExists(array $orgValues)
{
$defaultOrg = $this->embeddedForms['member_profile']->embeddedForms['organization']->getObject();
$table = $defaultOrg->getTable();
if(isset($orgValues['member_number'])
&& ($existingOrg = $table->findOneByMemberNumber($orgValues['member_number'])))
{
$user = $this->getObject();
$profile = $user->getMemberProfile();
$profile->Organization = $existingOrg;
// prepare the current values from the db to return
$orgValues = array_merge($orgValues, array_intersect_key($existingOrg->toArray(false), $orgValues));
$this->embedRelation('MemberProfile as member_profile', 'MemberProfileRegisttrationForm');
}
return $orgValues;
}
public function bind(array $taintedValues = null, array $taintedFiles = null)
{
if(isset($taintedValues['member_profile']['organization']))
{
$taintedValues['member_profile']['organization'] = $this->linkOrganizationIfExists($taintedValues['member_profile']['organization']);
}
parent::bind($taintedValues, $taintedFiles);
}
I have a domain object that has a property that i want to be used as the id by GORM, the reason being is that ill be saving lists of this object and i want existing rows to be updated if the id already exists in the database
Lets assume that my property i want as the PK is called listId
Ive seen several approaches to this, which is best?
1:
id generator: 'identity', column: 'listId'
2:
static mapping = {
id generator:'assigned'
}
def getKey = {
return listId;
}
or something entirely different?
static mapping = {
id generator: 'assigned', name: "listId", type: 'string'
}