I am trying to understand associations in sequelize and I am able to get one association to work but when I replicate the same query nothing gets returned. I don't understand the relationships that well even after reading the user guide
I can get the data from "stages" but not able to successfully join the "status" table and retrieve the data
I was able to find a workaround too where you can create the association from within findALL()
db.leads
.findAll({
attributes: ["id", "name", "title", "name", "title", "company", "workPhone", "mobilePhone", "otherPhone", "email", "dateCreated"],
include: [
{
model: db.stages,
association: db.leads.hasMany(db.stages, { foreignKey: "id", targetKey: "id" }),
on: {
[Op.and]: [
db.sequelize.where(
db.sequelize.col("stages.id"),
Op.eq, // '=',
db.sequelize.col("leads.stageID")
),
],
},
attributes: ["name"],
},
{
model: db.status,
association: db.leads.belongsToMany(db.status, { through: "id" }),
on: {
[Op.and]: [
db.sequelize.where(
db.sequelize.col("status.id"),
Op.eq, // '=',
db.sequelize.col("leads.statusID")
),
],
},
attributes: ["name"],
},
],
where: {
ownerID: req.query.ownerID,
},
subQuery: false,
duplicating: false,
})
This is what gets returned:
{
"id": "920cc536-48ae-40ee-8c5b-e1bfedbec602",
"name": "Dummy Lead",
"title": "Dummy",
"company": "Dummy",
"workPhone": "000-000-0000",
"mobilePhone": "000-000-0000",
"otherPhone": "000-000-0000",
"email": "Dummy#Dummy.com",
"dateCreated": "2022-06-18T13:30:09.676Z",
"stages": [
{
"name": "Qualify"
}
],
"status_types": []
}
Below are my tables:
Leads:
Stages:
Status:
In general, I believe the recommended approach to associations is to set them up in your models. This will make your queries easier to write, and also help from a DRY perspective. With the associations set up in models, your include would look something like
include: [
{
model: db.stages
attributes: ['name']
}
]
This would LEFT JOIN Stages with Leads. (NB: By adding a property of required: true to the object, you can make that perform an INNER JOIN).
The associations you're trying to call in these queries also do not really seem to match your table structure. If Leads hasMany Stages, then why is there a StageId in the Leads table? Having the foreign key in Leads would suggest that this is a hasOne or belongsTo relation from the Leads side. If Leads SHOULD have many Stages, then the foreign key should exist on the Stages table, so that multiple Stages can be associated to a single Lead.
Defining Leads with a belongsToMany relationship on Status also appears to be incorrect. BelongsToMany is the association method for Many to Many relationships through a junction table. If you do want to have a Many to Many relationship here (Where a Lead can have many Statuses, and Statuses can belong to many Leads), you will need to create that belongsToMany association on each side with a junction table (LeadStatuses). If a Lead should only have one status, however, the association should be lead.belongsTo() and status.hasMany().
I would take a long read about Sequelize Associations to try to take all of this in. It's challenging stuff that you will likely need to revisit several times, but it will make your life much easier once implemented correctly.
Related
I am using lighthouse-php as Api Gateway in a micro services architecture.
So for all my types I make a request internally through Guzzle.
But I am needing to implement filters that are suitable for any type and that give flexibility when making queries.
I need to implement a query like this:
query news (
order_by: {publication_date: desc}
where: {
_or: {categories_id: { _eq: 1 }, title: { _ilike: "news" } }
}
limit: 10
offset: 20
) {
id
category_name: name
photo
publication_date
text
title
}
But I have no idea how to implement this "where" filter that receives a composite object as in this example.
Remember that this query will not use any model within lumen, since it will be a custom query that will make a request to the microservice of news.
What I need is the way that my query receives whatever comes in where, limit and order, to send it on request. But I have no idea how to build something like this in the scheme.
Anyone have any idea how to do it?
Thanks friends.
Yes, you can.
Just now I'm making an component that will receive criterias to filter in graphql query so I need to fill filter's where params with those criterias.
Imagine the following schema:
type News{
id: ID!
title: String!
views: Int!
}
type Query{
getNews(where: _ #whereConditions(columns:["title", "views"])) : [News!] #all
}
We can make a query and fill where variables later
query GetNews($whereNews: [GetNewsWhereWhereConditions!]){
getNews(where: {OR: $whereNews}){
title
views
}
}
When querying we can fill the variables sending an object like
{
"where":[
{"column": "TITLE", "operator": "LIKE", "value": "Amazing title"},
{"column": "VIEWS", "operator": "GTE", "value": 10,
]
}
I'm trying to write a sequelize query which includes a relation from different table with hasMany relation. I want my query to return if some column in related table has matches my condition or there is not related row in the related table with foreign key from my main table.
Think about two different models, main one, which is folders, has id, name etc. columns and related table, which is folderOwners has id, folderId and groupId columns which shows which folders is owned by which groups. So, folders can have multiple owner groups.
include: [{
association: "owners",
required: true,
where: {
groupId: {[Op.in]: userGroups.map(group => group.id)}
}
}]
I can get the folders which owned by one of the groups that user is in but I want to get all folders if there is no row in related table, which means folder is not owned by anyone.
I've tried to change required to false and use Op.or for where like below
required: true,
where: {
[Op.or]: [
{groupId: {[Op.in]: userGroups.map(group => group.id)}},
{groupId: {[Op.eq]: null}}
],
}
So, are there any ways to achieve what I want?
If I understood correctly your problem, try this code :
Folder.findAll({include: [{model: Group, required: false}])
it will get all the folders with and without Groups
You can reference to nested model's column from parent model's "where" object using syntax like this: "$AssociatedTableName.columnName$"
Folder.findAll({
where: {
[Op.or]: [
{ '$Group.id$': null },
{
'$Group.id$': {
[Op.in]: [ids],
},
},
],
},
include: [
{
model: Group,
as: 'Group',
required: false,
},
],
});
I have a RESTful service that accepts a custom query, like this:
/entities/User?actions=
{
"$link": {
"entityType": "Manager",
"entity": {
"name": "John Smith"
},
"linkName": "managers",
"backLinkName": "account",
"$set": {
"propertyName": "aclWrite",
"propertyValue": {
"$ref": {
"propertyName": "entityId"
}
}
}
}
}
Which simply means:
Create a new Entity of type User
Create a new Entity of type Manager with the field name, linking the User to be created to this Manager through link name "managers"
Then back-linking the Manager entity to be created to the User with a link name "account" and setting the Manager entity write ACL (Access Control List) to the ID of the User to be created.
I created this query structure because I can't find any suitable Query language that can seem to support such action/procedure.
The question here is are there any Query language that can support such compound action/procedure or can GraphQL handle such?
As a specification, GraphQL doesn't care what fields your schema defines, what arguments those fields take or what your field resolvers do with those arguments. So it's perfectly feasible to design a schema that would let the client compose an equivalent mutation:
mutation {
link(
entityType: "Manager"
entity: {
name: "John Smith"
}
linkName: "managers"
backLinkName: "account"
set: {
propertyName: "aclWrite"
propertyValue: {
ref: {
propertyName: "entityId"
}
}
}
) {
# some fields here to return in the response
}
}
GraphQL does not support references to other nodes inside the same query, so you would still probably want a single mutation whose input mirrored your existing API. That said, using GraphQL for this may still be preferable because of request validation, which is all the more important with complex requests like this. Having an IDE like GraphiQL or GraphQL Playground that lets you write your queries using autocomplete is a big plus too.
Loopback has a way to make a light relationship using referencesMany where you can say something like:
{
"name": "SomeModel",
"plural": "SomeModel",
// ...,
"relations": {
"images": {
"type": "referencesMany",
"model": "Images",
"options": {
"validate": true
}
}
}
}
Which will allow you to store an array of ObjectId in MongoDB.
I can then do something like:
SomeModel.find({ include: 'images' }) or GET to /api/SomeModel/?filter[include]=images to include a response with nested image objects that are related to the SomeModel.
Is there a good way to do this in a singular case (not an array of values)? Relate one parent to a child? HasOne puts a someModelId on the child and I don't really want to pollute the Image model with BelongsTo as its polymorphic and belongs to all sorts of stuff.
I'm coming from the SQL world, so naturally mongo / noSQL has been an adventure.
I'm building a page to add/edit categories, that "posts" will later be assigned to.
What I've basically created is this:
{
_id: "asdf234ljsf",
title: "CategoryOne",
sortorder: 1,
active: true,
children: [
{
title: ChildOne,
sortorder: 1,
active: true
},
{
title: ChildTwo,
sortorder: 2,
active: true
}
]
}
So later, when creating a "post" I would assign that post to one or more parent categories, as well as optionally one or more child categories within the selected parent categories. Visitors to the site if they clicked on a parent category, it would show all posts within that parent category, and if they select a child category, it will only show posts within that child category.
The logic is obvious and simple, but in SQL I would have created tables like this:
table_Category ( CategoryID, Title, Sort, Active )
table_Category_Children ( ChildID, ParentID, Title, Sort, Active )
I've been reading the Discover Meteor book and it mentions that Meteor gives us many tools that work a lot better when operating at the collection level, as well as how the DDP operates at the top level of a document, meaning if something small changed down in a sub collection or array, potentially unneeded data will be sent back to all connected/subscribed clients.
So, this makes me think I should be organizing the categories like this:
Collection for parent categories
{
_id: "someid",
title: "CategoryOne"
sortorder: 1,
active: true
},
{
_id: "someid",
title: "CategoryTwo"
sortorder: 1,
active: true
}
Collection for Child Categories
{
_id: "someid",
parent: "idofparent"
title: "ChildOne"
sortorder: 1,
active: true
},
{
_id: "someid",
parent: "idofparent"
title: "ChildTwo"
sortorder: 1,
active: true
}
Or, perhaps its better like this:
Collection for parent categories
{
_id: "someid",
title: "CategoryOne"
sortorder: 1,
active: true,
children: [ { id: "childid" }, ... ]
}
I think understanding a best practice/method for Meteor and Mongo in this scenario will help me greatly across the board.
So conclusion: I have an admin page where I add/edit these categories. When clients create a post, they'll select the parent and child categories suitable for their post and make sure that I organize it properly from the beginning. Changing my thinking process from a traditional RDBMS to NoSQL is a big jump.
Thank you!
MongoDB stores all data in documents. This is a fundamental difference from relational database like SQL.
Imagine if you have 100 parent categories and 1000 child categories, once you update a parent category it will affect all linked child category's "idofparent", in a reactive way. In short, it's not sustainable.
Try to think of a way to avoid JOIN SQL equivalent in MongoDB.
Restructure you data perhaps similar to this way:
One big collection for all categories:
{
_id: id,
title: title,
sortorder: 1,
active: 1,
class: "parent > child" // make this as a field
...
}
// class can be "parent1", "parent2", "parent1 > child1" ... you get the idea
so each document store is completely individual.
Or if you absolutely need JOIN relational data structure, I don't think MongoDB is the right choice for you.