Create Both Parent/Child Associated Record in Sailsjs - sails.js

I'm having a hard time trying to figure out if sails/waterline even does this.
(so an adequate answer would simply be if this is possible or not, I have been reading docs, looking through github issues and looking through code, but still not sure)
I have a one to one association setup where an 'account' has a 'contact'
I'm trying to create a contact within sails blueprints (so basically just using the create() method)
account =
{ name: 'Corp'
contact:{
firstName: 'Bob',
lastName: 'Jones'
}
}
so should Account.create(account).exec() create the account and the associated contact? Because I'm getting the following error
TypeError: Cannot convert null to object
My model is setup like so
account.js
module.exports = {
migrate: 'safe',
tableName: 'accounts',
autoPK: false,
attributes: {
id: {
type: 'INTEGER',
primaryKey: true,
autoIncrement: true
},
contactId: 'INTEGER',
name: {type: 'STRING', maxLength: 100},
contact: {
model: 'contact',
columnName:'contactId'
}
}
};
I'm using sails 10.0-rc8 / waterline 10.0-rc15

Creating an associated instance at the same time as its parent (aka "nested create") should work, but it's tricky to get things just right when you're dealing with a legacy database. In your case, the contactId attribute declaration is probably causing the issue, since Waterline expects the foreign key field to be implicit, not explicit. Try removing:
contactId: 'INTEGER',
entirely and see where that gets you.

After some research I found out that as of version 0.10.0-rc15 of waterline you can NOT have a customized foreign keys. In the above model if I change the "contactId" column to just "contact" (basically make it look exactly like it does in the docs. Then it works.
I made the following bug report
https://github.com/balderdashy/waterline/issues/529

Related

sailsjs one-way associations confusion

I am having a hard time wrapping my head around associations with sailsjs.
I have 2 models
Services
attributes: {
status: {
defaultsTo: 'inactive'
},
userId:{
model: 'users',
via: 'id',
},
},
Users
attributes: {
email: {
type: 'string',
required: true,
unique: true
},
password: {
type: 'string'
}
},
So, a service is tied to a user (matching the id of the user).
I used to do a call like http://localhost:1337/Services?userId=userId
Now I would like to transition to associations using the above model attributes.
This works by calling the ID of the service just fine (it includes the users data as well), however if all i have is the user, how could I get the service
Doing the same call (http://localhost:1337/Services?userId=userId) returns and empty object.
Am I forced to actually have a one-to-one or one-to-many association? I don't understand why I can no longer use the userId field (stored in the DB) to do queries once I start using associations. I guess I am looking for the best of both worlds here.
EDIT:
Let me try make this more clear. Before trying to do associations, I could call this URL (using blueprint)
http://localhost:1337/Services?userId=userId
The Services model used to look like this
attributes: {
status: {
defaultsTo: 'inactive'
},
userId:{
type: 'string',
required: true,
},
},
Then when a user is created, a service for that user is created with the userId matching the ID in the Users table.
Now I would like to implement associations using the above model scheme.
However, because (my best guess) the userId field of the service is mapped to the Users model, I am unable to search for a Server using the userId field that is stored.
I hope that makes sense? In another words, tryin to call
http://localhost:1337/Services?userId=userId
returns nothing when using associations but does return a value when I don't use associations

sequelize find parent table from child

I would like to find the parent table information of an object.
I have User hasMany Book
where Book has writer and assigned to user id.
Book has type, which is like fantasy, romance, history, scientific fiction... etc
So I want to find out the Book with type Scientific Fiction but not only for that, I also want the writer, which is User.
How can I find the book with its writer where where condition is given for books only? It seems like 'include' in Book.findAll( include: User) is not working; this tells me that include is only working for finding child tables not parent.
Here are some code for user
const User = sequelize.define('User', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey : true }
}
associate: function(models) {
User.hasMany(models.Book, { foreignKey: 'userId' });
}
and book
const Book = sequelize.define('Book', {
id: { type: DataTypes.STRING(6), field: 'ID', primaryKey: true }, // primary key
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
type: { type: DataTypes.STRING(20), field: 'TYPE'
}
Book has some more child table and I try to find those additional information in includes, so I guess I really need to find from Book.findAll(...)
Instead of User.findAll(include: Book).
Can anyone help?
I think I was making a mistake.
As soon as I changed
userId: { type: DataTypes.STRING(6), field: 'USER_ID', primaryKey: true }
to
userId: { type: DataTypes.STRING(6), field: 'USER_ID' }
include is working for belongsTo; and it finds the parent from child.
It seems like Sequelize has some problem with relation if there is more than one primary key declared in model...
If anyone does think this solves your problem, please share in reply so I can be more sure about it.
Thanks.

Sailsjs - Prevent non-model fileds to be saved in mongo document

I recently started working with Sails and mongo.
I use Sails blueprints to generate part of my api.
The problem is, that the request body I send is being saved to the mongo collection, regardless of the fields defined in the model.
So for example, let's say I have the following Event model:
module.exports = {
attributes: {
title: {
type: 'string',
required: true
},
}
}
When I Send a POST request to the /event/ endpoint with the following params:
{"title":"Some Event", "random":"string"}
The saved mongo document contains also the "random":"string" value, even though it's not part of the model.
I've tried to come up with some common method to remove non-model attributes before creation for all models, but the possible solutions seemed not right and dirty.
Am I missing something?
Any help would be appreciated!
You can use schema option in your model. Just add it to model declaration and that's it.
// api/models/Model.js
module.exports = {
schema: true,
attributes: {
title: {
type: 'string',
required: true
}
}
};

Sails.js add attribute from another table to a model

I am trying to pull an extra attribute for a model from a different table.
I have been trying with associations but it seems wrong to create an extra model and associate that to my original model.
This is my model Company.js
module.exports = {
schema: true,
autoCreatedAt: false,
autoUpdatedAt: false,
autoPK: false,
attributes: {
name: {
type: 'string'
},
url: {
type: 'string'
},
summary: {
type: 'text'
}
}
};
I have another table in MySQL with two columns, crunchbase_url and company_id, I would like to pull the crunchbase_url into the Company model, what would be the best way to do it without migrating the DB (not an option unfortunately).
Thanks,
Well, turns out that the documentation is fine and all works like a charm by simply creating another model and using one to many association with joined with via.
However, there is a bug that threw me off:
When defaultLimit is set to -1, the find action return an empty list if there are associations.

Symfony 1.4, Propel, build-forms use an older yaml?

I use Symfony 1.4 with Propel. I deleted a table (name: company_show_field), deleted from database and schema.yml too. Then I added a new table named agency_company (it is exists in DB too). So I have this now:
company:
_attributes: { phpName: EdimaCompany }
id: { type: INTEGER, size: '11', autoIncrement: true, required: true }
name: { type: VARCHAR, size: '100', required: true }
...
agency_company:
_attributes: { phpName: EdimaAgencyCompany }
_propel_behaviors:
symfony:
form: false
filter: false
agency_id: { type: INTEGER, size: '11', required: true, primaryKey: true, foreignTable: company, foreignReference: id, onDelete: CASCADE }
company_id: { type: INTEGER, size: '11', required: true, primaryKey: true, foreignTable: company, foreignReference: id, onDelete: CASCADE }
Then I did:
symfony cc
symfony propel:build-model
symfony propel:build-forms
but the BaseEdimaCompanyForm class throws an exception: "Call to undefined method BaseEdimaCompany::getEdimaCompanyShowFields". I deleted some lines from this file (to test the generation is make a new file), and regenerate the models/forms again, but symfony generated a bad code again.
I'm sure this table (company_show_fields) isn't exists in the schema and in the DB. And I don't see the new table in this form class (agency_company).
Can somebody help me please? Why this happen? Where can symfony get the table name, what not exists?
PS: sorry for my English, this is not my native language.
It's easier to use symfony propel:build --all than just using build-model or build-forms when you have changes in your model, because it will generate all related scheme (e.g. model, filters, forms, db, etc).
Also, you don't need to delete the table in the real database manually, symfony will do it for you when you use build --all helper. If you want to remove a table from scheme, you just delete the table code in the scheme file, and delete all the associate file in the filter, form, and model folder inside /lib folder. This method will keep the connection between ORM and real database.