在MongoDB中获取具有n条最新评论的帖子

时间:2018-11-09 21:58:12

标签: mongodb join mongoose left-join mongoose-populate

因此,这是一个常见的问题,获取带有评论的帖子,我似乎在MongoDB中无法解决,这与在MySQL中使用left-join可以轻松解决的问题不同。

问题:

我想获取MongoDB中每条帖子的最新8条帖子,并带有 2条最近评论

  • 我不想重组帖子数据以包含匹配的评论ID的列表,因为我希望将来会有成千上万的评论。

  • 我真的不想求助于帖子,然后使用帖子ID执行8个单独的查询以找到2条最新评论。 (尽管我猜是次佳的解决方案

  • 我尝试设置postSchema.virtual('comments', ..),然后在执行查询时使用Post.find(..).populate('comments', options: {limit: 2})进行填充,但是不幸的是,限制返回了inconsistent results

数据:

Post:
{ body: "post1" }
{ body: "post2" }
{ body: "post3" }
...
{ body: "post8" }

Comment:
{ post_id: 1, message: "comment1" }
{ post_id: 2, message: "comment2" }
{ post_id: 2, message: "comment3" }
{ post_id: 3, message: "comment4" }

所有文档都有一个date字段,但是为了简洁起见将其删除

预期结果:

{ 
  body:"post1", 
  comments: [
    { post_id: 1, message: "comment1" }
  ]
}
{ 
  body:"post2", 
  comments: [
    { post_id: 2, message: "comment2" },
    { post_id: 2, message: "comment3" }
  ]
}
{ 
  body:"post3", 
  comments: [
    { post_id: 3, message: "comment4" }
  ]
}
...

1 个答案:

答案 0 :(得分:2)

如果您使用的是MongoDB 3.6或更高版本,则可以使用$lookup with custom pipeline将带有评论的帖子“加入”并接受2个最新的帖子(使用$limit

let items = [{ // overview
    title: 'Overview',
    path: `/root/overview`,
    module: "overview/menu",
    icon: "fa fa-home"
  }, // overview
  { // cardboards
    title: 'Cardboards',
    path: `/root/cardboards`,
    module: "cardboards/menu",
    icon: "fa fa-files-o",
    subs: [{
        title: 'Suppliers',
        path: `/root/cardboards/suppliers`,
        module: "suppliers/menu",
        icon: "fa fa-handshake-o"
      },
      {
        title: 'Employees',
        path: `/root/cardboards/employees`,
        module: "employees/menu",
        icon: "fa fa-address-book-o"
      },
    ]
  }, // cardboards
  { // charts
    title: 'Charts',
    path: `/root/charts`,
    icon: "fa fa-area-chart",
    module: "charts/menu",
    subs: [{
      title: 'Activity',
      path: `/root/charts/activity`,
      module: "charts/activity/menu"
    }, ]
  }, // charts
  { // settings
    title: 'Settings',
    path: `/root/settings`,
    module: "settings/menu",
    icon: "fa fa-cogs",
    subs: [{
      title: 'Permissions',
      path: `/root/settings/permissions`,
      module: "settings/permissions/menu",
      icon: "fa fa-file-text-o"
    }]
  } // settings
];


function flatten(tree) {
  let res = [];
  function traverse(arr) {
    res.push(...arr);
    arr.forEach(o => traverse(o.subs || []));
  }
  traverse(tree);
  return res;
}

let pathIndex = flatten(items).reduce((acc, curr) => {
  if (curr.path) acc[curr.path] = curr;
  return acc;
}, {});

let breadcrumbs = ["/", "/root", "/root/cardboards", "/root/cardboards/employees", "/root/cardboards/employees/123"];
console.log(breadcrumbs.filter(path => path in pathIndex)
                       .map(path => ({title: pathIndex[path].title, path})));