繁体   English   中英

在父记录属性列表中包含子记录计数,而不获取所有子记录

[英]Include child records count in the parent record attributes list without fetching all child records

我已经设置了一个非常基本的小型游乐场,用于后续实验,以了解它在关联记录获取时的行为。 但我无法达到预期的输出。

可重现的代码

const Sequelize = require('sequelize');

const { fn } = Sequelize;
const sequelize = new Sequelize('playground', 'postgres', 'postgres', {
  host: 'localhost',
  dialect: 'postgres',
  pool: {
    max: 9,
    min: 0,
    idle: 10000
  }
});

const Posts = sequelize.define('posts', {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true
    },
    title: {
      type: Sequelize.STRING
    },
    content: {
      type: Sequelize.STRING
    }
  }, 
  {
    freezeTableName: true,
    timestamps: false
  }
);

const Comments = sequelize.define('comments', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true
  },
  postId: {
    type: Sequelize.INTEGER,
    references: {
       model: 'posts',
       key: 'id'
    }
  },
  comment: {
    type: Sequelize.STRING
  }
}, 
{
  freezeTableName: true,
  timestamps: false
}
);

Posts.hasMany(Comments, {
   foreignKey: 'postId'
})


let criteria = {
  group: ['posts.id', 'comments.id'],
  attributes: [
    [fn('count', 'comments.id'), 'TotalComments']
  ],
  include: [
    {
      model: Comments,
    }
  ]
}


Posts.findAll(criteria).then(posts =>{
    console.dir(JSON.parse(JSON.stringify(posts)), {depth: null, colors: true});
});

遇到问题

问题很简单,我想在父属性中添加子记录计数,例如返回的每个帖子中所有评论的计数,但我得到的输出是返回一个固定计数,即 1。我可以简单地迭代所有帖子并通过读取包含的评论的总长度来设置 TotalComments,但我想使用 sequelize 查询来做到这一点,因为这样我可以应用一些过滤器,例如评论在 6 到 10 之间的帖子

显示的输出

[
  {
    id: 101,
    title: 'The revolution in brain',
    TotalComments: '1', //this count is not matched with below included comments count
    comments: [
      { id: 15, postId: 101, comment: 'It helped me a lot' },
      { id: 13, postId: 101, comment: 'very disapointing' },
      { id: 12, postId: 101, comment: 'welldone' },
      { id: 14, postId: 101, comment: 'This post sucks' }
    ]
  },
  {
    id: 102,
    title: 'Making your hands dirty on Java',
    TotalComments: '1',
    comments: []
  },
  {
    id: 100,
    title: 'Earlier models of medical surgery',
    TotalComments: '1',
    comments: [
      { id: 10, postId: 100, comment: 'Appreciated your work' },
      { id: 11, postId: 100, comment: 'good' }
    ]
  }
]

所需输出

[
  {
    id: 101,
    title: 'The revolution in brain',
    TotalComments: 4,
    comments: [
      { id: 15, postId: 101, comment: 'It helped me a lot' },
      { id: 13, postId: 101, comment: 'very disapointing' },
      { id: 12, postId: 101, comment: 'welldone' },
      { id: 14, postId: 101, comment: 'This post sucks' }
    ]
  },
  {
    id: 102,
    title: 'Making your hands dirty on Java',
    TotalComments: 0,
    comments: []
  },
  {
    id: 100,
    title: 'Earlier models of medical surgery',
    TotalComments: 2,
    comments: [
      { id: 10, postId: 100, comment: 'Appreciated your work' },
      { id: 11, postId: 100, comment: 'good' }
    ]
  }
]

生成的 SQL

SELECT "posts"."id", "posts"."title", count('comments.id') AS "TotalComments", "comments"."id" AS "comments.id", "comments"."postId" AS "comments.postId", "comments"."comment" AS "comments.comment" FROM "posts" AS "posts" LEFT OUTER JOIN "comments" AS "comments" ON "posts"."id" = "comments"."postId" GROUP BY "posts"."id", "comments"."id";

经过大量搜索,我自己解决了这个问题,如果遇到类似的问题,我希望它能帮助其他所有人,基本上我使用 sequelize 文字插入一些原始查询来解决问题,修改后的查询条件示例如下

let criteria = {
  group: ['posts.id', 'comments.id'],
  attributes: [
    'id',
    'title',
    [literal('(select count(comments.id) from comments where "comments"."postId" = "posts"."id")'), 'TotalComments']
  ],
  include: [
    {
      model: Comments,
    }
  ]
}


Posts.findAll(criteria).then(posts =>{
    console.dir(JSON.parse(JSON.stringify(posts)), {depth: null, colors: true});
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM