如何通过许多$projects来改善此聚合

How to improve this aggregate with many $projects

本文关键字:何通过 许多 projects      更新时间:2023-09-26

我创建了一个聚合函数,我觉得它很长而且不干。我想知道有什么方法可以改进它。

我的Thread模型有一个名为 revisions 的子文档。该函数尝试获取具有status的最新版本 APPROVED .

这是完整模型。

{
  "_id": ObjectId("56dc750769faa2393a8eb656"),
  "slug": "my-thread",
  "title": "my-thread",
  "created": 1457249482555.0,
  "user": ObjectId("56d70a491128bb612c6c9220"),
  "revisions": [
    {
      "body": "This is the body!",
      "status": "APPROVED",
      "_id": ObjectId("56dc750769faa2393a8eb657"),
      "comments": [
      ],
      "title": "my-thread"
    }
  ]
}

这是我想要改进的聚合函数。

Thread.aggregate([
  { $match: {
    slug: thread
  } },
  { $project: {
    user: '$user',
    created: '$created',
    slug: '$slug',
    revisions: {
      $filter: {
        input: '$revisions',
        as: 'revision',
        cond: { $eq: [ '$$revision.status', 'APPROVED' ] }
      }
    }
  } },
  { $sort: { 'revisions.created': -1 } },
  { $project: {
    user: '$user',
    created: '$created',
    slug: '$slug',
    revisions: { $slice: ["$revisions", 0, 1] }
  } },
  { $unwind: '$revisions'},
  { $project: {
    body: '$revisions.body',
    title: '$revisions.title',
    user: '$user',
    slug: '$slug',
    created: '$created'
  }}
])
好吧,

你真的不能,因为中间有$sort$unwind阶段是故意的。这基本上也是"错误的",因为$sort不能对数组重新排序,直到您先$unwind它。

然后最好改用$group$first,只从每个文档中的排序中获取第一个元素:

Thread.aggregate([
  { "$match": {
    "slug": thread
  } },
  { "$project": {
    "user": 1,
    "created": 1,
    "slug": 1,
    "revisions": {
      "$filter": {
        "input": "$revisions",
        "as": "revision",
        "cond": { "$eq": [ "$$revision.status", "APPROVED" ] }
      }
    }
  } },
  // Cannot sort until you $unwind
  { "$unwind": "$revisions" },
  // Now that will sort the elements
  { "$sort": { "_id": 1, "revisions.created": -1 } },
  // And just grab the $first boundary for everything
  { "$group": {
    "_id": "$_id",
    "body": { "$first": "$revisions.body" },
    "title": { "$first": "$revisions.title" },
    "user": { "$first": "$user" },
    "slug": { "$first": "$slug" },
    "created": { "$first": "$created" }
  }}
])

您总是可以使用$push来改革数组,然后应用$arrayElemAt而不是$slice来仅生成单个元素,但是考虑到首先在$group之后还需要另一个$project,这有点浮夸。

因此,即使有"一些"操作您可以在不使用$unwind的情况下执行,不幸的是,"排序"从$filter等函数生成的数组目前无法完成,直到您先$unwind数组。


如果您不需要""revisions.created"上的$sort(示例文档中明显缺少),那么您可以改用普通投影:

Thread.find(
    { "slug": slug, "revisions.status": "APPROVED" },
    { "revisions.$": 1 },
)

只有在对数组元素进行排序时,您才需要其他任何东西,因为$位置运算符无论如何都会返回第一个匹配的元素。