I have the following model defined with Sequelize:
module.exports = function (sequelize, DataTypes) {
var Genre = sequelize.define('Genre', {
name: {
type: DataTypes.STRING,
allowNull: false
}
}, {
classMethods: {
associate: function (models) {
Genre.hasMany(models.Genre, {as: 'subGenre'});
Genre.belongsTo(models.Genre, {as: 'parentGenre'});
}
}
});
return Genre;
}
The idea is that there will be parent genres, and each may have several sub-genres. When I run sync(), the table is created fine, but there is an extra column (GenreId) that I can't quite explain:
"id";"integer";
"name";"character varying";255
"createdAt";"timestamp with time zone";
"updatedAt";"timestamp with time zone";
"GenreId";"integer";
"parentGenreId";"integer";
The sensible way to interpret the model is to only have a parentGenreId column, but I am not sure how to define that bi-directional relationship (genre may have parent, genre may have many children) with only one column being added.
How can I rework the model to allow the relationship to be defined correctly?
I think you could use through (not tested)
module.exports = function (sequelize, DataTypes) {
var Genre = sequelize.define('Genre', {
name: {
type: DataTypes.STRING,
allowNull: false
}
}, {
classMethods: {
associate: function (models) {
Genre.hasMany(models.Genre, {as: 'children', foreignKey: 'ParentId'});
Genre.belongsTo(models.Genre, {as: 'parent', foreignKey: 'ParentId'});
}
}
});
return Genre;
}
So you could have Genre#getChilren and Genre#getParent
EDIT: Due to #mick-hansen, through applies for belongsToMany, not useful for this case. My fault. Corrected using his recommendation
Related
Hello I'm not new to Flutter but super new to Graphql. I have this Resolver in NestJs
#Mutation(() => Recipe)
createRecipe(
#Args('createRecipeInput') createRecipeInput: CreateRecipeInput,
) {
return this.recipesService.create(createRecipeInput);
}
The DTO looks like this.
#InputType()
export class CreateRecipeInput {
#Field(() => [String], { nullable: true })
ingredientNames?: string[];
#Field(() => [String], { nullable: true })
instructionNames?: string[];
}
My mutation
const String createRecipe = r'''
mutation CreateRecipe(
$ingredientNames: [String!]!,
$instructionNames: [String!]!,
) {
action: createRecipe(createRecipeInput: {
instructionNames: $instructionNames,
}) {
ingredientNames
instructionNames
}
}
''';
final MutationOptions options = MutationOptions(
document: gql(createRecipe),
operationName: 'CreateRecipe',
variables: <String, dynamic>{
'ingredientNames': ingredientNames,
'instructionNames': instructionNames,
},
);
await client.mutate(options);
I get this error
{"errors":[{"message":"Cannot query field \"ingredientNames\" on type \"Recipe\". Did you mean \"ingredients\"?","locations":[{"line":8,"column":5}],"extensions":
Is like the request is not mapping to the DTO but the actual entity. I tried this example using the playground and postman and in both this code works. Not sure if the library is busted or I'm just missing something.
Thanks.
I am trying to insert a validation into PUT request(to update some data stored in MongoDB):
DTO:
export enum reportFields {
'startDate',
'targetDateOfCompletion',
'duration',
}
export class updateScheduleDto {
#IsOptional()
#IsString()
readonly frequency?: string;
#IsOptional()
#IsArray()
#IsEmail({}, { each: true })
#IsString({ each: true })
readonly emails?: string[];
#IsOptional()
#IsEnum(reportFields, { each: true })
#IsArray()
#IsString({ each: true })
readonly reportFields?: string[];
#IsOptional()
#Type(() => Number)
#IsNumber()
updatedAt?: number;
}
Controller:
#Put('reports/:id/schedule')
async updateScheduleData(
#Param('id') id: string,
#Body(new ValidationPipe()) updateData: updateScheduleDto,
) {
return this.reportService.updateScheduleData(id, updateData);
}
Service:
async updateScheduleData(id: string, updateData: updateScheduleDto) {
try {
updateData.updatedAt = this.utils.getCurrentTime();
const newData = await this.reportScheduleModel.findByIdAndUpdate(
id,
updateData,
{
new: true,
},
);
console.log(`Data has been updated to ${newData}`);
return newData;
} catch (error) {
throw new Error('>>>' + error);
}
}
But the validation not working over the keys. If I pass a non-valid key(like below) in the body object, even then the program executes without any error, how do I fix this? What am I missing?
{
"emaaaalls":["randomemail123#gmail.com"]
}
You need to pass the options { forbidUnknownValues: true } to the ValidationPipe. This will make class-validator throw an error when unknown values are passed in. You can read through the options here
You can make whitelist: true in ValidationPipe options.
When set to true, this will automatically remove non-whitelisted properties (those without any decorator in the validation class).
you can read more about this https://docs.nestjs.com/techniques/validation#stripping-properties
in the addBussiness method, I create a business object and then use the result to create a UserBusiness object in the database using sequelize.
I want to return the Business object created after the UserBusiness object is done creating.
As it stands now I think due to the asynchronous nature of Javascript, the business object is returned before the UserBusiness object is done creating.
Is there a way to return the object from the 1st callback in the 2nd callback?
addBusiness(_,args) {
// this is needed to put it correctly in the geometry point format that the database expects
var point = { type: 'Point', coordinates: [args.input.location.longitude,args.input.location.latitude] };
args.input.location = point;
return Business.create(args.input, {
include: [{
association: Hours,
as: 'hours'
}]
}).then(business => {
UserBusiness.create({userId: args.input.userId, businessId: business.businessId})
return business; // this might get returned before UserBusiness.create is done executing
})
},
here is my mapping defined in sequelized:
UserAccountModel.belongsToMany(BusinessModel, { through: UserBusinessModel, foreignKey: 'user_id'});
BusinessModel.belongsToMany(UserAccountModel, { through: UserBusinessModel , foreignKey: 'business_id'});
You can return UserBusiness object after creation and then return UserBusiness.bussiness or save business object in a variable and return the variable after UserBusiness object is created.
addBusiness(_,args) {
var point = { type: 'Point', coordinates: [args.input.location.longitude,args.input.location.latitude] };
args.input.location = point;
return Business.create(args.input, {
include: [{
association: Hours,
as: 'hours'
}]
}).then(business => {
return UserBusiness.create({userId: args.input.userId, businessId: business.businessId})
}).then(UserBusiness => {
return UserBusiness.business;
})
}
OR
addBusiness(_,args) {
var _business;
var point = { type: 'Point', coordinates: [args.input.location.longitude,args.input.location.latitude] };
args.input.location = point;
return Business.create(args.input, {
include: [{
association: Hours,
as: 'hours'
}]
}).then(business => {
_business = business;
return UserBusiness.create({userId: args.input.userId, businessId: business.businessId})
})
.then(() => {
return _business;
})
}
I have a model Route belongs to Region, when I define the associate, I thought you could just simply do the following:
"use strict";
module.exports = (sequelize, DataTypes) => {
const Route = sequelize.define("Route", {
title: {
type: DataTypes.STRING,
allowNull: false
}
});
Route.associate = models => {
Route.belongsTo(models.Region);
};
return Route;
};
With the route:
app.post("/api/regions/:regionId/routes", routesController.create);
Controller:
create(req, res) {
console.log(req.params.regionId);
return Route.create({
title: req.body.title,
regionId: req.params.regionId
})
.then(route => res.status(201).send(route))
.catch(err => res.status(400).send(err));
},
But when I post to that route, I keeps getting back the route with Null for regionId. Even though I can log the regionId with POST params.
I know the fix is to add foreignKey as following to explicit declare to use regionId as foreignKey:
Route.associate = models => {
Route.belongsTo(models.Region, {
foreignKey: "regionId"
});
};
But I thought it could just default regionId as foreignKey without declaring it. Am I missing something?
I have mongodb sitting behind an existing API and want to migrate the API to use sailsjs.
The data structure isn't anything crazy - just standard stuff using default mongodb ObjectIds as primary keys.
Will I be able to use this existing db with sails by just wiring up sails models? Do I need to specify the _id field? And, if so, what datatype should I use?
E.g. Existing mongodb with user collection with the following schema:
_id
name
fname
lname
age
Can I just wire up using something like the following for it to work?:
// User.js
var User = {
attributes: {
name: {
fname: 'STRING',
lname: 'STRING'
},
age: 'INTEGER'
}
};
module.exports = Person;
First: you dont have to define _id (waterline do this for you)
Waterline wants to help you using the same Functions and Models for all types of databases. A "Sub-Field" is not supported in mysql for example. So this don't work.
You can do this:
// User.js
var User = {
attributes: {
name: 'json',
age: 'integer'
}
};
module.exports = User;
If you want to validate "name" you can add your own validation:
// User.js
var User = {
types: {
myname: function(json){
if(typeof json.fname == "string" && typeof json.lname == "string"){
return true;
}else{
return false;
}
}
},
attributes: {
name: {
type: "json",
myname: true
},
age: 'integer'
}
};
module.exports = User;