Sails.js add attribute from another table to a model - sails.js

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.

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

Sort populated record in sails waterline

I created a Sails application with two models Publication and Worksheet. They are having a one-to-one relationship. Sails-postgresql is the adapter I'm using. I'm using waterline orm to fire query to the database. I'm When I am trying to load publications data along with worksheet and then sort the records depending on a field in the Worksheet using sort() I'm getting an error.
My model is:
Publication.js
module.exports = {
attributes: {
id: {
type: 'integer'
unique: true
},
worksheetId: {
type: 'integer',
model : 'worksheet'
},
status: {
type: 'string',
defaultsTo: 'active',
in : ['active', 'disabled'],
}
}
}
Worksheet.js
module.exports = {
attributes: {
id: {
type: 'integer',
unique: true
},
name: 'string',
orderWeight: {
type: 'integer',
defaultsTo: 0
}
}
}
So now I want to load all the publication where status is "active" and populate worksheet in the data.
So I'm executing the query:
Publication.find({
where: {
status: 'active'
}
})
.populate('worksheetId').limit(1)
.exec(function (error, publications) {
})
And I'm getting a data like :
{
id : 1,
status : "active",
worksheetId : {
id : 1
name : "test",
orderWeight : 10
}
}
So till now it's all working fine. Now I want to increase the limit to 10 and want to sort the data depending on "orderWeight" which is in the populated data. Initially I sorted the whole data depending on publication id and the query worked.
Publication.find({
where: {
status: 'active'
}
})
.populate('worksheetId').sort('id ASC').limit(10)
.exec(function (error, publications) {
})
So I fired similar query to sort the data on "orderWeight"
Publication.find({
where: {
status: 'active'
}
})
.populate('worksheetId').sort('worksheetId.orderWeight ASC').limit(10)
.exec(function (error, publications) {
})
And this query is giving me error that worksheetId.orderWeight is not a column on the publication table. So I want to fire this sort query on the populated data not on the publication table.
Please let me know how I can get my expected result.
Apart from sort() method I also want to run some find command to the populated data to get those publication where the worksheet name matches with certain key as well.
Basically, what you're trying to do, is query an association's attribute. This has been in the waterline roadmap since 2014, but it's still not supported, so you'll have to figure out a workaround.
One option is to query the Worksheet model, and populate the Publication, since sails doesn't let you query across models without using raw queries (i.e. .sort('worksheetId.orderWeight ASC') doesn't work). Unfortunately, you might have to move the active flag to the Worksheet. For example:
Worksheet.find({
status: 'active'
})
.populate('publication') // you should also add publication to Worksheet.js
.sort('orderWeight ASC')
.limit(10)
Alternatively, you could combine Worksheet and Publication into one model, since they're one-to-one. Probably not ideal, but sails.js and Waterline make it very difficult to work with relational data - I'd estimate that half of the queries in the project I'm working on are raw queries due to sails' poor support of postgres. The framework is pretty biased towards using MongoDB, although it claims to "just work" with any of the "supported" DBs.

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
}
}
};

Create Both Parent/Child Associated Record in Sailsjs

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

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.