在Sequelize.js中联接表之间的多对多表中计数关系

时间:2018-11-30 22:57:37

标签: javascript mysql node.js sequelize.js

我正在使用sequelize.js构建一个项目,该项目包括一个Tags表和一个Stories表。它们之间存在多对多关系,我是通过StoryTag直通表顺序创建的。到目前为止,这一切都可以正常工作,但是我想获得大多数popluar标签的列表,例如StoryTag表中与它们关联的故事数,并按使用该标签的故事数对其进行排序。

这是我要执行的MySQL语法。这在MySQL Workbench中非常有效:

SELECT tagName, COUNT(StoryTag.TagId) 
FROM Tags 
LEFT JOIN StoryTag on Tags.id = StoryTag.TagId 
GROUP BY Tags.tagName ORDER BY COUNT(StoryTag.TagId) DESC;

这是在sequelize.js中起作用的方法。这是一个原始查询,并不理想,但是由于它不处理任何敏感信息,因此不必担心,只是非常微不足道。

//DIRECT QUERY METHOD (TEST)
app.get("/api/directags", function (req, res) {
    db.sequelize.query("select tags.id, tags.TagName, COUNT(stories.id) as num_stories 
    from tags left join storytag on storytag.TagId = tags.id 
    left join stories on storytag.StoryId = stories.id 
    group by tags.id order by num_stories desc;", { 
        type: db.Sequelize.QueryTypes.SELECT
    }).then(function(result) {
        res.send(result);
    });
}); 

此输出

[
  {
    "id": 3,
    "TagName": "fiction",
    "num_stories": 3
  },
  {
    "id": 5,
    "TagName": "Nursery Rhyme",
    "num_stories": 2
  },
  ...
  {
    "id": 4,
    "TagName": "nonfiction",
    "num_stories": 0
  }
]

应有的。
不太有效的是:

//Sequelize count tags 
//Known issues: will not order by the count
//Includes a random 'storytag' many-to-many table row for some reason
app.get("/api/sequelizetags", function (req, res) {
    db.Tag.findAll({
        attributes: ["id","TagName"],
        include: [{
            model: db.Story, 
            attributes: [[db.sequelize.fn("COUNT", "stories.id"), "Count_Of_Stories"]],
            duplicating: false
        }],
        group: ["id"]
    }).then(function (dbExamples) {
        res.send(dbExamples);
    });
}); 

哪个输出:

[
    {
        "id": 1,
        "TagName": "horror",
        "Stories": [
            {
                "Count_Of_Stories": 1,
                "StoryTag": {
                    "createdAt": "2018-11-29T21:09:46.000Z",
                    "updatedAt": "2018-11-29T21:09:46.000Z",
                    "StoryId": 1,
                    "TagId": 1
                }
            }
        ]
    },
    {
        "id": 2,
        "TagName": "comedy",
        "Stories": []
    },
    {
        "id": 3,
        "TagName": "fiction",
        "Stories": [
            {
                "Count_Of_Stories": 3,
                "StoryTag": {
                    "createdAt": "2018-11-29T21:10:04.000Z",
                    "updatedAt": "2018-11-29T21:10:04.000Z",
                    "StoryId": 1,
                    "TagId": 3
                }
            }
        ]
    },
    {
        "id": 4,
        "TagName": "nonfiction",
        "Stories": []
    },
   ...
    {
        "id": 8,
        "TagName": "Drama",
        "Stories": [
            {
                "Count_Of_Stories": 1,
                "StoryTag": {
                    "createdAt": "2018-11-30T01:13:56.000Z",
                    "updatedAt": "2018-11-30T01:13:56.000Z",
                    "StoryId": 3,
                    "TagId": 8
                }
            }
        ]
    },
    {
        "id": 9,
        "TagName": "Tragedy",
        "Stories": []
    }
]

这是不正常的,故事的数量被掩埋了。这似乎是来自数据库的常见请求,但我不知道如何使用sequelize.js正确执行此操作。

使我失败的资源:
Sequelize where on many-to-many join
Sequelize Many to Many Query Issue
How to query many-to-many relationship data in Sequelize
Select from many-to-many relationship sequelize
续集的官方文档:http://docs.sequelizejs.com/manual/tutorial/
一些不太正式和易读的续集文档:https://sequelize.readthedocs.io/en/v3/docs/querying/

3 个答案:

答案 0 :(得分:1)

  1. 如果您指的是同一事物(664-num_stories等),请使用相同的名称。
  2. 要订购,请使用Count_Of_Stories option
  3. 在顶级属性中包括order,以使其在实例的顶级。
  4. 我在文档中找不到count选项。

您的情况:

include[].duplicating

答案 1 :(得分:1)

在选项中使用through: {attributes: []}

答案 2 :(得分:0)

这是最终起作用的方法,以防其他人有这个问题。我们还为include Story添加了一个位置,但这是可选的。 该资源比官方的续篇文档更容易理解:https://sequelize-guides.netlify.com/querying/
我还了解到,在使用续集时,熟悉诺言确实很有帮助。

db.Tag.findAll({
        group: ["Tag.id"],
        includeIgnoreAttributes:false,
        include: [{
            model: db.Story,
            where: {
                isPublic: true
            }
        }],
        attributes: [
            "id",
            "TagName",
            [db.sequelize.fn("COUNT", db.sequelize.col("stories.id")), "num_stories"],
        ],
        order: [[db.sequelize.fn("COUNT", db.sequelize.col("stories.id")), "DESC"]]
    }).then(function(result){
        return result;
    });