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

我的Thread模型有一个名为revisions的子文档。该函数尝试获取statusAPPROVED的最新修订版。

这是完整的模型。

{
  "_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来生成单个元素,但是考虑到在第一个$project之后需要另一个$group,这有点多余。地点。

因此,即使有一些“操作”也可以不使用$unwind进行,但是,不幸的是,“排序”由诸如$filter之类的函数生成的数组目前尚无法完成,除非先对$unwind进行操作。



如果您不“需要” $sort上的"revisions.created"(尤其是示例文档中缺少),则可以改用普通投影:

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


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

09-13 03:49