I'm using sequelize.js for ORM, and I have some questions while I use it.
Models looks like this
var Keyword = db.define('keyword', {
name: db.STRING,
});
var KeywordSearchableMap = db.define('keyword_searchable_map', {
keyword_id: db.INTEGER,
searchable: db.STRING,
searchable_id: db.STRING,
score: db.STRING,
});
var Searchable = db.define('searchable') {
name: db.STRING,
});
Keyword.belongsToMany(Searchable, {
through: {
model: KeywordSearchableMap,
},
foreignKey: 'keyword_id'
});
Searchable.belongsToMany(Keyword, {
through: {
model: KeywordSearchableMap,
},
foreignKey: 'searchable_id'
});
And I want to get 'Searchable' things by Keyword.getSearchables() order by 'score' field in 'KeywordSearchableMap'
Is there any methods to get sorted searchable objects?
Related
I have two models defined in GraphQL Cars and Brands (their association is cars.brand_id = brands.id).
The schema only works when I define:
Cars.hasMany(models.brands, {
sourceKey: 'brand_id',
foreignKey: 'id'
})
Whereas it doesn't work if I define it in the following way:
Cars.hasOne(models.brands, {
sourceKey: 'brand_id',
foreignKey: 'id'
}),
Here I share a bit more of the schema (I am using makeExecutableSchema to split the files definitions):
Associations:
CarBrands.js
CarBrands.associate = models => {
CarBrands.hasOne(models.cars, {
foreignKey: 'brand_id',
});
}
Cars.js
Cars.associate = models => {
Cars.belongsTo(models.brands),
Cars.hasMany(models.car_images, {
foreignKey: {
name: 'car_id',
allowNull: false
},
onDelete: "cascade"
});
};
Car Model:
export const typeDef = `
type Cars {
user_id: Int!,
title: String!,
brands: [CarBrands!],
car_images: [CarImages],
}
`;
The SQL is well-formed, and car_images returns the data correctly whereas brands does not. Any idea why is that?
Any hint will be forever appreciated.
Thanks
You can find the document one-to-one-relationships at there: https://sequelize.org/master/manual/assocs.html#one-to-one-relationships
.In the document introduces 4 options to define one-to-one.
Try it:
Brands.hasOne(Cars, {
foreignKey: 'brand_id'
});
Cars.belongsTo(Brands);
I am looking to return all articles from the database associated with one or more keywords, but I am not sure there right way to go about this?
I am using Sequelize 3.x, with node.js 3.7.0.
The data model looks at follows:
const Article = sequelize.define('article', {
...
}
const Keyword = sequelize.define('keyword', {
name: Sequelize.STRING,
lang: Sequelize.STRING
}
const ArticleKeyword = sequelize.define('article_keyword', {
articleId: Sequelize.INTEGER,
keywordId: Sequelize.INTEGER
}
(Article).belongsToMany(
Keyword, { through: ArticleKeyword, as: 'keyword' });
(Keyword).belongsToMany(
Article { through: ArticleKeyword, as: 'article' });
Then the query I tried:
var keywordFilter;
if (req.body.keywords) {
var keywords = req.body.keywords);
if (typeof keywords === 'string') {
keywords = keywords.split(/ *, */);
}
keywordFilter = { name: { $in: keywords } };
}
Article.findAll({
where: {
deleted: false
},
include: [{
model: Keyword,
as: 'keywords',
where: keywordFilter,
attributes: ['name'],
through: {
attributes: []
}
}]
}).then(function(articles) {
...
});
The issue I am finding here is rather than selecting just the articles with the matching keywords it returns all the articles and then simply selects the keywords specified in the query for the results.
Can anyone suggest the right way to go about this?
Hi can you try passing
require:true
in the include block for inner join and check
Ref : https://stackoverflow.com/a/31680398/4583460
I am working on a Waterline query which filters objects by a collection attribute. In this simplified example, I have two models, Video and Category:
// Video.js
module.exports = {
attributes: {
title: {
type: 'string'
},
categories: {
collection: 'Category',
via: 'videos'
}
}
};
// Category.js
module.exports = {
attributes: {
name: {
type: 'string'
},
videos: {
collection: 'Video',
via 'categories'
}
}
};
I want to find all the videos which are associated with a certain category. I have the category id stored in a variable named categoryID and am trying this query:
Video.find('categories': categoryID).exec(function (err, videos) {
// videos should contain all videos associated with the categoryID
});
However, I always end up with an empty result, even though there are videos associated with the category for which I am looking. I know that waterline does currently not support deep queries for values in collection attributes, but I thought at least a query for the id of the object would work. Am I wrong?
If so, is there an alternative way to achieve the desired result without using native queries?
I am aware that I could add a collection attribute to Category and build my query from the Category side. However, this is only the beginning of a more complicated search where I also narrow down the result using other attributes stored in a Video object, such as the user id of the creator of a video. In the end, I iterate through the video results using pagination. So I am looking for a way to retrieve videos of certain category which can be combined with other search attributes stored in a Video object.
Modify Category.js to:
module.exports = {
attributes: {
name: {
type: 'string'
},
videos: {
collection: 'Video',
via: 'categories'
}
}
};
Modify Video.js
module.exports = {
attributes: {
title: {
type: 'string'
},
categories: {
collection: 'Category',
via: 'videos'
}
}
};
When adding a video,
var title = req.param('title');
var categories = req.param('categories').split(','); //ids of categories in format 1,3,8 etc
Video.create({name: title, categories: categories}, function(err, succ){
if(err){
return res.serverError(err);
}else {
return res.json(200, succ);
}
});
To find all videos with a specific category, use the populate() helper in waterline.
var categoryId = req.param('catId');
Category.find({id: categoryId}).populate('videos').exec(function(err, results){
if(err){
return res.serverError(err);
}else {
return res.json(200, results);
}
});
Video model :
module.exports = {
attributes: {
name: {
type: 'string'
},
categories: {
collection: 'category',
via: 'videos'
},
toJSON: function() {
var obj = this.toObject();
return obj;
}
}
};
Category model :
module.exports = {
attributes: {
name: {
type: 'string'
},
videos: {
collection: 'Video',
via: 'categories'
}
}
};
And your query will look like :
var arr = ['56667a2cbaea1fcd11c54851','56667b1053c6c37a1283ea75'];
Video.find().populate("categories",{id:arr}).exec(function(e, r) {
res.json(r);
})
I have a Node entity with a many to many relationship with itself through Edge
var Node = db.define('nodes', {
'name': sequelize.STRING
});
var Edge = db.define('edges', {
'weight': sequelize.STRING
});
Node.hasMany(Node, { as: 'parents', foreignKey: 'parent_id', through: Edge});
Node.hasMany(Node, { as: 'children', foreignKey: 'child_id', through: Edge});
I want to get a nodes children which are created after a specific time using a query like the following
node.getChildren({
include: [Edge],
where: ['createdAt > ?', 1413000965754]
}).complete(function(err, children){
// ...
});
but I cant get it to work.
I have Books which have an author and an editor. I'd like to query for all books with a title like '%gone% and author.name like '%paul%' - I couldn't find documentation about doing this, but I've tried various formats based on what I've googled.
Attempt using a filter on includes:
var includes = [
{"model": db.User, as: 'Author', through: {"where": {"name": { like: '%paul%'}}}}
];
var filter = { title: { like: '%gone%'}};
return Book.findAll({ include: includes, order: 'id desc', where: filter});
While the restriction on title works, the author name is ignored (no errors).
Variation without the 'through' (same result - doesn't affect resultset):
var includes = [
{"model": db.User, as: 'Author', "where": {"name": { like: '%paul%' } } }
];
And how I initiatively thought it might work (causes error):
var filter = { title: { like: '%gone%'}, 'author.name' : { like : '%paul%' } };
Any clues or pointers to documentation to help me do this??
Thanks.
Model:
var User = sequelize.define('User', {
name: {
type: DataTypes.STRING
},
...
classMethods: {
associate: function (models) {
User.hasMany(Book, { as: 'Author', foreignKey: 'author_id' });
User.hasMany(Book, { as: 'Editor', foreignKey: 'editor_id' });
},
...
}
var Book = sequelize.define('Book', {
title: {
type: DataTypes.STRING,
len: [20]
},
...
classMethods: {
associate: function (models) {
Book.belongsTo(User, { as: 'Author', foreignKey: 'author_id' });
Book.belongsTo(User, { as: 'Editor', foreignKey: 'editor_id' });
},
...
I got it to work by removing the 'as' in the User associations to Book to:
User.hasMany(Book, { foreignKey: 'author_id' });
User.hasMany(Book, { foreignKey: 'editor_id' });
Then I can filter as expected with:
var includes = [
{model: db.User, as: 'Author'},
{model: db.User, as: 'Editor'}
];
var filter = { title: { like: '%gone%'}, 'Author.name' : { like : '%paul%' } };
return Book.findAll({ include: includes, order: 'id desc', where: filter});
It helped to turn on logging of SQL statements as described here: How can I see the SQL generated by Sequelize.js?