我创建了一个聚合函数,我觉得它很长而且很不干燥。我想知道我有什么方法可以改善它。
我的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
来生成单个元素,但是考虑到在第一个$project
之后需要另一个$group
,这有点多余。地点。因此,即使有一些“操作”也可以不使用
$unwind
进行,但是,不幸的是,“排序”由诸如$filter
之类的函数生成的数组目前尚无法完成,除非先对$unwind
进行操作。如果您不“需要”
$sort
上的"revisions.created"
(尤其是示例文档中缺少),则可以改用普通投影:Thread.find(
{ "slug": slug, "revisions.status": "APPROVED" },
{ "revisions.$": 1 },
)
只有在对数组元素进行排序时,您才需要其他任何东西,因为
$
位置运算符将始终返回第一个匹配的元素。