I've got the following models associated with sequelize.
Event hasMany Characters through characters_attending_boss
Boss hasMany Characters through characters_attending_boss
Characters hasMany Event through characters_attending_boss
Characters hasMany Boss through characters_attending_boss
These tables are successfully joined and I can retrieve data from them. But when I retrieve the JSON-results the name of the through model gets added to each object, like this:
{
id: 1
title: "title"
-confirmed_for: [ //Alias for Event -> Character
-{
id: 2
character_name: "name"
-confirmed_for_boss: [ // Alias for Boss -> Character
-{
id: 9
name: "name"
-character_attending_event: { // name of through-model
event_id: 1
char_id: 2
}
}
]
-character_attending_boss: { // name of through-model
event_id: 1
char_id: 2
}
}
So I'm looking for a way to hide these "character_attending_boss" segments if possible, preferably without altering the results post-fetch.
Is this possible?
Same issue is solved here: https://github.com/sequelize/sequelize/issues/2541
For me adding through: {attributes: []} to include block works well on Sequelize 2.0
Pass { joinTableAttributes: [] } to the query.
Related
Let’s say I have foo and I make it include bar model,They are many to many relationship.
While bar model contains a column called clients, which is an array in nodejs.
foo.findAll({
where : where,
include : [{ model: bar}]
})
How should I use foo.findAll to get all data which bar must be an empty array.
You can simply Do it like this I am suggesting this because your question is unclear
foo.findAll({
where: where,
include: [{
model: bar,
where: { name: { [Op.is]: null } }
}]
})
above code will return data of model bar where name as no value or the field is null
I have 5 db tables:
Template, Capability, Deployment, Level, Requirement
Template (PK) -> has many Capability (FK)
Capability (PK) -> has many Deployments (FK) && Capability has many Levels (FK)
Level (PK) -> has many Requirement (FK)
I want to retrieve all templates, with the related foreign keys all the way down to the Requirements.
However, I would like to limit the number of Levels to just the ones that are not deleted (isDeleted : false).
This works if there is DATA retrieved, BUT if there are no records returned from the Levels tables based on the Where (isDeleted), Sequelize will return an empty array for the Deployments table as well. This query correct data if records are found from the Levels table. However, shouldn't the records from the deployment table be returned regardless since it is a different table?
Template.hasMany(Capability, { foreignKey : {name : 'templateId'} })
Capability.hasMany(Deployment, { foreignKey : {name : 'capabilityId'} });
Capability.hasMany(Level, {foreignKey : {name : 'capabilityId'} });
Level.hasMany(Requirement, {foreignKey : {name : 'levelId'}});
const allModules =
await Template.findAll({
include : [ {
model: Capability,
as: 'capabilities',
include : [
{
model: Deployment,
as : 'deployments'
},{
model: Level,
as : 'levels',
where : { isDeleted : false }, // this is the failing part ( if no records are returned both the Deployment recordset and the Level recordset fail)
include : [{
model : Requirement,
as : 'requirements',
}],
},]
}],
})
You might be asking for something impossible. You said:
Capability.hasMany(Level, ...
Level.hasMany(Requirement ....
If there is no Level (or, if the level is marked as deleted), the link between Capability and Requirement is broken, so those Requirements cannot be retrieved. Under what capability would they appear?
OTOH, If you're looking for other outer join situations, try required : false. For example, you could add this to your query to retrieve Capabilities that have no deployments as follows:
...
include : [ {
model: Capability,
as: 'capabilities',
include : [
{
model: Deployment,
as : 'deployments',
required : false // outer join
}
...
I have the following scenario, my application has two entities: box and items with N to N relationship. I am using sequelize with MySQL.
I am using pseudocode to represent the tables:
Box {
id: Integer primary key
name: String
}
Item {
id: Integer primary key
name: String
}
I have set up the schemas with relations hasMany in both directions using the following through relation:
Box.hasMany(Item, { through: Box_Item });
Item.hasMany(Box, { through: Box_Item });
Box_Item {
id_box: Integer,
id_item: Integer,
item_order: Integer
}
With primary_key(id_box, id_item).
I tested it and I can call myBox.getItems() on my instance object myBox and easily get all the items it has.
I can make calls as
BoxModel.findOne({
where: { id: 1 },
include: [{ model: ItemModel }]
});
And it automatically understands there is a relation between the models through Box_Item and get everything correctly, except that I'm not getting the results sorted by item_order field. This field is a number from 1 to N that represents the item order inside that box.
I tried
BoxModel.findOne({
where: { id: 1 },
include: [
{
model: ItemModel,
order: 'item_order'
}
]
});
But it seems sequelizejs does not support order inside include yet (checked on their github repo).
I tried to force
BoxModel.findOne({
where: { id: 1 },
order: '`box_model`.`item_order`'
include: [ { model: ItemModel } ]
})
looking through the query sequelize creates but it just put the ORDER BY in two different places (inside INNER JOIN and at the end of the query, don't know why...) and I got an error.
So I searched for this on stackoverflow (1), found a few questions but I don't get a good way for doing that using the ORM.
How could I get the items sorted by item_order field when asking for specific box items?
After a few days trying to get it done I found an answer on stackoverflow that helped me.
After creating the relationships between Box and Item I can easily call on an instance:
myBox.getItems({
order: '`box_model`.`item_order`'
});
And then I get the result I'm expecting. But I had to look through the query sequelize is creating based on the models and get the correct field based on their renaming rules.
If you want you can pass the as parameter and rename your tables.
I have a query I'm trying to perform based on a one to many relationship.
As an example there is a model called Users and one called Projects.
Users hasMany Projects
Projects have many types which are stored in a type (enum) column. There are 4 different types that potentially a user may have that I want to load. The catch is I want to include the most recent project record (createdAt column) for all networks that potentially will be there. I have not found a way to structure the query for it to work as an include. I have however found a way to do a raw query which does what I want.
I am looking for a way without having to do a raw query. By doing the raw query I have to map the returned results to users I've returned from the other method, or I have to do a simple include and then trim off all the results that are not the most recent. The latter is fine, but I see this getting slower as a user will have many projects and it will keep growing steadily.
This allow serialize a json for anywhere action about a model. Read it, very well
sequelize-virtual-fields
// define models
var Person = sequelize.define('Person', { name: Sequelize.STRING });
var Task = sequelize.define('Task', {
name: Sequelize.STRING,
nameWithPerson: {
type: Sequelize.VIRTUAL,
get: function() { return this.name + ' (' + this.Person.name + ')' }
attributes: [ 'name' ],
include: [ { model: Person, attributes: [ 'name' ] } ],
order: [ ['name'], [ Person, 'name' ] ]
}
});
// define associations
Task.belongsTo(Person);
Person.hasMany(Task);
// activate virtual fields functionality
sequelize.initVirtualFields();
new to ember js, and working on an app using ember-data. If I test with same data using FixtureAdapter, everything populates in the html template ok. When I switch to RESTAdapter, the data looks like it's coming back ok, but the models are not being populated in the template? Any ideas? Here's the code:
App.Store = DS.Store.extend({
revision:12,
//adapter: 'DS.FixtureAdapter'
adapter: DS.RESTAdapter.extend({
url:'http://bbx-dev.footballamerica.com/builderapirequest/bat'
})
});
App.Brand = DS.Model.extend({
name: DS.attr('string'),
numStyles: DS.attr('string'),
vendorId: DS.attr('string')
});
App.BrandsRoute = Ember.Route.extend({
setupController:function(controller){
},
model:function(){
return App.Brand.find();
}
});
And here is the data coming back, but not being inserted into the template!
returnValue: [{numStyles:1, name:Easton, vendorId:6043}, {numStyles:1, name:Louisville Slugger, vendorId:6075},…]
0: {numStyles:1, name:Easton, vendorId:6043}
1: {numStyles:1, name:Louisville Slugger, vendorId:6075}
2: {numStyles:1, name:Rawlings, vendorId:6109}
3: {numStyles:7, name:BWP Bats , vendorId:6496}
4: {numStyles:1, name:DeMarini, vendorId:W002}
status: "ok"
And here is the template:
{{#each brand in model.returnValue }}
<div class="brand-node"{{action select brand}}>
<h2>{{brand.name}}</h2>
<p>{{brand.numStyles}} Styles</p>
</div>
{{/each}}
Any help would be greatly appreciated! I'm not getting any errors, and the data seems to be coming back ok, just not getting into the template. Not sure if the returned dataset needs "id" param?
I am also using the Store congfig to alter the find() from plural to singular:
DS.RESTAdapter.configure("plurals", {
brand: "brand"
});
The way the API was written, its expecting "brand" and not "brands"... maybe its something to do with this??
Thanks in advance.
You have stated:
Not sure if the returned dataset needs "id" param?
Yes you are guessing right, you data coming back from the backend need's an id field set. And if the id field name is different then id you should also define this in ember like so:
App.Store = DS.Store.extend({
revision:12,
//adapter: 'DS.FixtureAdapter'
adapter: DS.RESTAdapter.extend({
url:'http://bbx-dev.footballamerica.com/builderapirequest/bat'
}),
serializer: DS.RESTSerializer.extend({
primaryKey: function (type) {
return '_my_super_custom_ID'; // Only needed if your id field name is different than 'id'
}
})
});
I suppose your Fixtures have an id defined thus it works, right?
Note: you don't need to define the id field at all explicitly, ember add's automatically the id field to a model, so your model is correct.
Here a website that is still a WIP but can be good reference for this conventions
and as stated there:
The document MUST contain an id key.
And this is how your JSON should look like for a collection of records:
{
"brands": [{
"id": "1",
"numStyles": "1",
"name": "Easton",
"vendorId" :"6043"
}, {
"id": "2",
"numStyles": "4",
"name": "Siemens",
"vendorId": "6123"
}/** and so on**/]
}
Note: as you have shown you JSON root is called returnValue this should be called brand or brands if you are not adapting the plurals. See here for reference for the JSON root I'm talking about.
Hope it helps