Sails Js populate with conditions - javascript

I'm trying to multiple populate in sails js using sails-hook-deep-orm. I want to filter the province id.
I am using the latest version of Sails and Node. And I using MySQL for database.
This is my model :
// Province.js
attributes: {
name: {
type: 'string',
required: true
},
description: {
type: 'string',
required: false
},
cities: {
collection: 'city',
via: 'province'
}
}
// City.js
attributes: {
name: {
type: 'string',
required: true
},
description: {
type: 'string',
required: false
},
province: {
model: 'province'
},
communities: {
collection: 'community',
via: 'city'
}
}
// Community.js
attributes: {
name: {
type: 'string',
required: true
},
description: {
type: 'string',
required: false
},
cities: {
collection: 'city',
via: 'province'
}
}
I have try with :
Community.find()
.populate('city.province', {'city.province.id' : 1});
Community.find()
.populate('city.province', { where: { 'city.province.id': 1 } });
The code still not filtering. I Hope this case can be solved. Thank you :)

When you populate an association of your object, the name needs to be the name of the association in the parent object and not the name of the model you are referring to.
In your situation, Community has the association named 'cities'.
The next step is to filter the list of cities, this is the where statement as the second argument of the populate.
Community.find()
.populate('cities', {
where: {
province: 1
}
}
)

Related

Limit Depth on Recursive GraphQL Schema Query using graphql-sequelize resolver (Node.js, express-graphql)

I have 2 Models, User and Post. I want to be able to get User information when querying a post, and be able to get all of a User's posts when querying a user.
they have an association as follows:
User.hasMany(Post, {
foreignKey: 'user',
as: 'posts'
});
Post.belongsTo(User, {
foreignKey: 'id',
sourceKey: 'user',
as: 'userObject'
})
Post.addScope('defaultScope', {
include: [{ model: User, as: 'userObject' }],
}, { override: true })
User.addScope('defaultScope', {
include: [{ model: Post, as: 'posts' }],
}, { override: true })
Here are my Models
User.js
module.exports.userType = new GQL.GraphQLObjectType({
name: 'User',
fields: () => {
const { postType } = require('../Post/Post');
return {
id: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'user unique id'
},
ci_username: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
unique: true,
description: 'case INSENSITIVE username of the user'
},
username: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'case SENSITIVE username of the user'
},
password: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'password for the user'
},
first_name: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'first name of user'
},
last_name: {
type: GQL.GraphQLString,
description: 'last name of user (optional)'
},
profile_picture: {
type: GQL.GraphQLString,
description: 'profile picture for the user'
},
posts: {
type: GQL.GraphQLList(postType),
description: 'list of users posts'
}
}
},
})
/** define User model for the database */
module.exports.User = db.define('user', {
id: {
type: Sequelize.UUID,
primaryKey: true,
unique: true,
},
ci_username: {
type: Sequelize.STRING,
unique: true,
},
username: Sequelize.STRING,
password: Sequelize.STRING,
first_name: Sequelize.STRING,
last_name: Sequelize.STRING,
profile_picture: Sequelize.STRING,
}, {
// Tells sequelize not to query the "CreatedAt" or "UpdatedAt" Columns
timestamps: false
})
Post.js
module.exports.postType = new GQL.GraphQLObjectType({
name: 'Post',
fields: () => {
const { userType } = require('../User/User');
return {
id: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'post unique id'
},
name: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'name of the post'
},
user: {
type: userType,
description: 'user object of who created the post'
},
created_at: {
type: new GQL.GraphQLNonNull(GQL.GraphQLString),
description: 'the datetime the post was created',
}
}
},
})
/** define User model for the database */
module.exports.Post = db.define('post', {
id: {
type: DataTypes.UUID,
primaryKey: true,
unique: true,
},
name: DataTypes.STRING,
user: {
type: DataTypes.STRING,
references: {
model: 'users',
key: 'id'
}
},
created_at: {
type: DataTypes.TIME,
defaultValue: DataTypes.NOW
}
}, {
// Tells sequelize not to query the "CreatedAt" or "UpdatedAt" Columns
timestamps: false
})
Here are my Queries:
allUsers.js
const allUsers = {
type: new GQL.GraphQLList(userType),
args: {
username: {
description: 'username of the user',
type: GQL.GraphQLString,
},
// An arg with the key limit will automatically be converted to a limit on the target
limit: {
type: GQL.GraphQLInt,
default: 10
},
// An arg with the key order will automatically be converted to a order on the target
order: {
type: GQL.GraphQLString
}
},
// use graphql-sequelize resolver with the User model from database
resolve: resolver(User)
}
allPosts.js
const allPosts = {
type: new GQL.GraphQLList(postType),
args: {
username: {
description: 'username of the user',
type: GQL.GraphQLString,
},
// An arg with the key limit will automatically be converted to a limit on the target
limit: {
type: GQL.GraphQLInt,
default: 10
},
// An arg with the key order will automatically be converted to a order on the target
order: {
type: GQL.GraphQLString
}
},
// use graphql-sequelize resolver with the Post model from database
resolve: resolver(Post)
}
I'm currently getting a Maximum call stack size exceeded. I assume because the resolver in the queries are recursively getting details on posts and users infinitely.
Does anyone know of any way to put a depth limitation on the resolver? Or is it just not possible to have a recursive query like this?
You would have to remove the default scope from the included model as shown here like this:
Post.addScope('defaultScope', {
include: [{ model: User.scope(null), as: 'userObject' }],
}, { override: true })
User.addScope('defaultScope', {
include: [{ model: Post.scope(null), as: 'posts' }],
}, { override: true })
To support additional depth, you'd need to implement resolvers for the fields in question, for example:
function resolve (user) {
if (user.posts) {
return user.posts
}
return user.getPosts()
}

How do I access the data in the .pre('validation') hook?

I am having trouble with performing operations during the pre('validate') hook. I need to do some prevalidation (making sure at least one of 2 different fields is populated, but not necessarily both, for example).
const AccessorySchema = new Schema({
accessory: {
type: String,
required: true,
},
category: {
type: String,
required: true,
enum: [
'Offense',
'Defence',
'Miscellaneous'
]
},
space: {
type: Number,
required: true,
validate: {
validator: Number.isInteger,
message: 'Space must be an integer'
}
},
priceFixed: {
type: Number,
required: false,
validate: {
validator: Number.isInteger,
message: 'Fixed Price must be an integer'
}
},
priceMultiplier: {
type: [Schema.Types.Mixed],
required: false
},
weightFixed: {
type: Number,
required: false,
validate: {
validator: Number.isInteger,
message: 'Fixed Weight must be an integer'
}
},
weightMultiplier: {
type: [Schema.Types.Mixed],
required: false
},
vehicles: {
type: [String],
required: true,
enum: ["car","cycle"]
}
});
AccessorySchema.pre('validate', (next) => {
console.log(this);
next();
});
And I send it this object :
{
accessory: "some name",
category: "Miscellaneous",
priceMultiplier: [3,5],
weightMultiplier: [3,5],
space: 0,
vehicles: ["car"]
}
this logs {} and populates the mongo DB. But I can't check any of the properties in pre validation.
mongoose version is ^4.7.7, nodejs 6.10.2, mongodb version is 3.2.9
How can I access the data in the pre validation hook?
do not use arrow function, it doesn't bind the context.
Change your code to below
AccessorySchema.pre('validate', function(next){
console.log(this);
next();
});

waterline.js how to associate a model that can have sub models of the same model itself?

Is there a way to associate a model that can have sub models of itself?
In this example there's a model of 'component' that might have sub components of the same type:
{
identity: 'component',
connection: 'default',
attributes: {
id: {
type: 'string',
unique: true,
primaryKey: true,
required: true
},
name: 'string',
from_device: {
model: 'device',
via: 'id'
},
dataItems: {
collection: 'dataitem'
},
subComponents:{
collection: 'component',
via: 'id',
// through: 'componentsubcomponent'
}
}
}
Ofc. That works nested comment eg. on Facebook.
Example:
// models/Comment.js
module.exports = {
attributes: {
parent: {
model: "comment"
},
children: {
collection: 'comment',
via: 'parent'
},
content: {
type: "text",
required: true
},
author: {
model: "user",
required: true
}
}
};

How to use the 'via' attribute in a collection with more than one PK?

How to use the 'via' attribute in a collection with more than one PK?
Below is an example of a hasMany datamodel.
The Model Definition.
Persistence.prototype.collections.Device = Waterline.Collection.extend({
identity: 'device',
connection: 'default',
attributes: {
name: {
type: 'string',
required: true,
primaryKey: true
},
uuid:{
type: 'string',
required: true,
primaryKey: true
},
dataItems: {
collection: 'dataitem',
via: 'id'
}
}
});
The Collection Definition with the two 'via' attributes.
Persistence.prototype.collections.DataItem = Waterline.Collection.extend({
identity: 'dataitem',
connection: 'default',
attributes: {
id: {
type: 'string',
unique: true,
primaryKey: true
},
category: 'string',
type: 'string',
from_device: {
model: 'device'
via: 'name', // ??????
via: 'uuid' // ?????????
}
}
});
Do not use via like this, because value of via will be overwritten. So in your case will be like that
from_device: {
model: 'device'
//via: 'name', <-- omitted
via: 'uuid'
}

Foreign Keys in SailsJS Models and Databases

I've been trying to get a better understanding of how to setup Foreign Keys in SailsJS. I am currently working on a project for class in which my group needs to create an evaluation system with instructor and students profile to view the results. I've seen some examples online, but I have seen varies formats and I'm not sure what the correct format is suppose to look like.
User Model
/**
* User.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
// The user's anonymous ID (e.g. 1)
anonymousID: {
type: 'integer',
autoIncrement: true
},
// The user's first name (e.g. Bob)
firstName: {
type: 'string',
required: true
},
//The user's last name (e.g. Smith)
lastName: {
type: 'string',
required: true,
},
// The user's full name (e.g. Bob Smith)
fullName: {
type: 'string',
required: true
},
// The user's assigned NetID (e.g. abc123)
netID: {
type: 'string',
primaryKey: true,
required: true,
unique: true
},
// The user's nine digit SchoolID (e.g. 000-000-000)
schoolID: {
type: 'integer',
size: 9,
required: true,
unique: true
},
// The user's email address (e.g. netID#university.edu)
email: {
type: 'string',
email: true,
required: true,
unique: true
},
// The encrypted password for the user (e.g. asdgh8a249321e9dhgaslcbqn2913051#T(#GHASDGA)
encryptedPassword: {
type: 'string',
required: true
},
// The timestamp when the the user last logged in
// (i.e. sent a username and password to the server)
lastLoggedIn: {
type: 'date',
required: true,
defaultsTo: new Date(0)
},
// The user's academic title (e.g. student)
title: {
state:{
type : 'string',
required: true,
enum: ['Student', 'Faculty', 'Staff', 'Dean'],
defaultsTo: 'Staff'
}
},
// The user's academic classification (e.g. freshman)
classification: {
state: {
type: 'string',
required: true,
enum: ['Freshman', 'Sophomore', 'Junior', 'Senior', 'Graduate', 'N/A']
defaultsTo: 'N/A'
}
},
}
};
Schedule Model
/**
* Schedule.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
// The CRN ID (e.g. 32458)
courseID: {
type: 'integer',
autoIncrement: true,
primaryKey: true
},
// The Course Reference Name (e.g. MBW 1001)
course: {
type: 'string',
size: 8,
required: true
// Add FK code from Course Table
},
// The Course Name (e.g. Magical Basket Weaving)
title: {
type: 'string',
required: true
// Add FK code from Course Table
},
// The Course Instructor (e.g. ab123)
intructorID: {
type: 'string',
required: true
// Add FK code from User Table
},
// The Term refers to the semester (e.g. Fall 2015)
term: {
type: 'string',
required: true
},
}
};
Courses Model
/**
* Course.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
// The Evaluation ID (e.g. 1)
courseNum: {
type: 'integer',
autoIncrement: true
},
// The Department Name (e.g. Arts and Sciences)
department: {
type: 'string',
required: true
},
// The Course Reference Name (e.g. MBW 1001)
course: {
type: 'string',
primaryKey: true,
size: 8,
unique: true
},
// The Course Name (e.g. Magical Basket Weaving)
title: {
type: 'string',
required: true
},
}
};
Enrolled Model
/**
* Enrolled.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
// The Transaction ID (e.g. 32458)
transactionID: {
type: 'integer',
autoIncrement: true,
primaryKey: true
},
// The CRN ID (e.g. 32458)
courseID: {
type: 'integer',
required: true
// Add FK code from Schedule Table
},
// The Course Instructor (e.g. ab123)
instructorID: {
type: 'string',
required: true
// Add FK code from Schedule Table
},
// The Course Instructor (e.g. ab123)
studentID: {
type: 'string',
required: true
// Add FK code from User Table
},
// The Term refers to the semester (e.g. Fall 2015)
term: {
type: 'string',
required: true
},
// The Right to Submit an Evaluation (e.g. True or False)
evaluationStatus: {
type: 'boolean',
},
}
};
Evaluation Model
/**
* Evaluation.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
// The Evaluation ID (e.g. 1)
evaluationID: {
type: 'integer',
autoIncrement: true,
primaryKey: true
},
// The user's anonymous ID (e.g. 1)
anonymousID: {
type: 'string',
required: true,
// Add FK code from user table
},
// The Course Instructor (e.g. ab123)
intructorID: {
type: 'string',
required: true
// Add FK code from User Table
},
// The course's assigned CRN (e.g. 12343)
courseID: {
type: 'integer',
required: true,
size: 5
// Add FK code from schedule table
},
// The Course Reference Name (e.g. MBW 1001)
course: {
type: 'string',
size: 8,
},
// The rating of question 1
ratingOne: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 2
ratingTwo: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 3
ratingThree: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 4
ratingFour: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 5
ratingFive: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 6
ratingSix: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 7
ratingSeven: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 8
ratingEight: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 9
ratingNine: {
type: 'integer',
required: true,
size: 2
},
// The rating of question 10
ratingTen: {
type: 'integer',
required: true,
size: 2
},
// The positive feedback from student
positiveFeedback: {
type: 'string',
defaultsTo: 'N/A',
size: 4000
},
// The negative feedback from student
negativeFeedback: {
type: 'string',
defaultsTo: 'N/A',
size: 4000
},
// The General Rating of Evaluation (e.g. 8.76, SUM(ratings)/TotalRatings)
genRateEval: {
type: 'float',
required: true,
size: 4
},
// The Inaproprate Flag (e.g. True or False)
inaproprateFlag: {
type: 'boolean',
},
}
};
I've included all five models I'm working with so everyone can get a complete picture of how everything will/should connect.
From my understanding, the foreign key should be setup like the code snippet below.
Schedule Model (with Foreign Keys)
/**
* Schedule.js
*
* #description :: TODO: You might write a short summary of how this model works and what it represents here.
* #docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
// The CRN ID (e.g. 32458)
courseID: {
type: 'integer',
autoIncrement: true,
primaryKey: true
},
// The Course Reference Name (e.g. MBW 1001)
course: {
// Add FK code from Course Table
model: 'Course',
via: 'course'
},
// The Course Name (e.g. Magical Basket Weaving)
title: {
// Add FK code from Course Table
model: 'Course',
via: 'title'
},
// The Course Instructor (e.g. ab123)
intructorID: {
// Add FK code from User Table
model: 'User',
via: 'netID'
},
// The Term refers to the semester (e.g. Fall 2015)
term: {
type: 'string',
required: true
},
}
};
I'm not completely sure though if that's the proper way to setup foreign keys.
Yes, its the right way of setting up a foreign key in sails js. That being said, it varies on the type of association i.e., whether the relation is one to one or one to many.
Taking the examples from sailsjs website,
One to One relation:
myApp/api/models/pet.js
module.exports = {
attributes: {
name:'STRING',
color:'STRING',
owner:{
model:'user'
}
}
}
myApp/api/models/user.js
module.exports = {
attributes: {
name:'STRING',
age:'INTEGER',
pony:{
model: 'pet'
}
}
}
One to Many relation:
myApp/api/models/pet.js
module.exports = {
attributes: {
name:'STRING',
color:'STRING',
owner:{
model:'user'
}
}
}
myApp/api/models/user.js
module.exports = {
attributes: {
name:'STRING',
age:'INTEGER',
pets:{
collection: 'pet',
via: 'owner'
}
}
}
Sailsjs Associations
Your main problem is how to use association so first use the reference/documentation on the sails js official website http://sailsjs.org/documentation/concepts/models-and-orm/associations, and i think all your queries will be solved.

Categories

Resources