首先,让我们以人们可以使用它并产生所需结果的方式显示您的数据:
{ value: 1,
_id: ObjectId('5cb9ea0c75c61525e0176f96'),
name: 'Test',
category: 'Development',
subcategory: 'Programming Languages',
status: 'Supported',
description: 'Test',
change:
[ { version: 1,
who: 'ATL User',
when: new Date('2019-04-19T15:30:39.912Z'),
what: 'Item Creation' },
{ version: 2,
who: 'ATL Other User',
when: new Date('2019-04-19T15:31:39.912Z'),
what: 'Name Change' } ],
}
请注意,"when"
日期实际上是不同的,所以会有一个$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/值并且它们不只是相同。现在我们可以回顾一下案例
案例 1 - 获取“单数”$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value
这里的基本情况是使用$arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/ and $indexOfArray https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfArray/运算符返回匹配的$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value:
db.items.aggregate([
{ "$match": {
"subcategory": "Programming Languages", "name": { "$exists": true }
}},
{ "$addFields": {
"change": {
"$arrayElemAt": [
"$change",
{ "$indexOfArray": [
"$change.when",
{ "$max": "$change.when" }
]}
]
}
}}
])
Returns:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : {
"version" : 2,
"who" : "ATL Other User",
"when" : ISODate("2019-04-19T15:31:39.912Z"),
"what" : "Name Change"
}
}
基本上是"$max": "$change.when"
返回该值数组中的“最大值”。然后,您可以通过以下方式找到该值数组的匹配“索引”$indexOfArray https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfArray/它返回first找到匹配的索引。该“索引”位置(实际上只是一个数组"when"
以相同顺序转置的值)然后与$arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/arrayElemAt/从中提取“整个对象”"change"
指定索引位置处的数组。
情况 2 - 返回“倍数”$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ entries
几乎同样的事情$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/,除了这次我们$filter https://docs.mongodb.com/manual/reference/operator/aggregation/filter/返回倍数“可能的”匹配的值$max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value:
db.items.aggregate([
{ "$match": {
"subcategory": "Programming Languages", "name": { "$exists": true }
}},
{ "$addFields": {
"change": {
"$filter": {
"input": "$change",
"cond": {
"$eq": [ "$$this.when", { "$max": "$change.when" } ]
}
}
}
}}
])
Returns:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : [
{
"version" : 2,
"who" : "ATL Other User",
"when" : ISODate("2019-04-19T15:31:39.912Z"),
"what" : "Name Change"
}
]
}
So the $max https://docs.mongodb.com/manual/reference/operator/aggregation/max/当然是相同的,但是这次该运算符返回的奇异值用于$eq https://docs.mongodb.com/manual/reference/operator/aggregation/eq/内比较$filter https://docs.mongodb.com/manual/reference/operator/aggregation/filter/。这会检查每个数组元素并查看current "when"
价值 ("$$this.when"
)。在哪里"equal"然后返回该元素。
与第一种方法基本相同,但不同之处在于$filter
allows “多种的”要返回的元素。所以一切与same $max https://docs.mongodb.com/manual/reference/operator/aggregation/max/ value.
情况 3 - 对数组内容进行预排序。
现在您可能会注意到,在我包含的示例数据中(改编自您自己的数据,但具有实际的“最大”日期),“最大”值实际上是last数组中的值。这可能会自然发生,因为$push https://docs.mongodb.com/manual/reference/operator/update/push/( 默认情况下 )“追加”到现有数组内容的末尾。所以"newer"条目往往位于end数组的。
这当然是default行为,但你有充分的理由"may"想要改变这一点。简而言之best的方式来获得“最近”数组条目实际上是返回第一个元素从数组中。
您实际上需要做的就是确保“最近”实际上添加了first而不是last。有两种方法:
-
Use $position https://docs.mongodb.com/manual/reference/operator/update/position/“预先挂起”数组项:这是一个简单的修改器$push https://docs.mongodb.com/manual/reference/operator/update/push/使用0
position为了始终添加到front:
db.items.updateOne(
{ "_id" : ObjectId("5cb9ea0c75c61525e0176f96") },
{ "$push": {
"change": {
"$each": [{
"version": 3,
"who": "ATL User",
"when": new Date(),
"what": "Another change"
}],
"$position": 0
}
}}
)
这会将文档更改为:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : [
{
"version" : 3,
"who" : "ATL User",
"when" : ISODate("2019-04-20T02:40:30.024Z"),
"what" : "Another change"
},
{
"version" : 1,
"who" : "ATL User",
"when" : ISODate("2019-04-19T15:30:39.912Z"),
"what" : "Item Creation"
},
{
"version" : 2,
"who" : "ATL Other User",
"when" : ISODate("2019-04-19T15:31:39.912Z"),
"what" : "Name Change"
}
]
}
请注意,这需要您事先实际“反转”所有数组元素,以便“最新”元素已经位于前面,从而保持顺序。值得庆幸的是,第二种方法在某种程度上涵盖了这一点......
-
Use $sort https://docs.mongodb.com/manual/reference/operator/update/sort/按顺序修改每个文件$push https://docs.mongodb.com/manual/reference/operator/update/push/:这是另一个修改器,它实际上对每个新项目添加进行原子“重新排序”。正常使用方法与任何新项目基本相同$each https://docs.mongodb.com/manual/reference/operator/update/each/如上所述,甚至只是一个“空”数组以应用$sort https://docs.mongodb.com/manual/reference/operator/update/sort/仅适用于现有数据:
db.items.updateOne(
{ "_id" : ObjectId("5cb9ea0c75c61525e0176f96") },
{ "$push": {
"change": {
"$each": [],
"$sort": { "when": -1 }
}
}}
)
结果是:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : [
{
"version" : 3,
"who" : "ATL User",
"when" : ISODate("2019-04-20T02:40:30.024Z"),
"what" : "Another change"
},
{
"version" : 2,
"who" : "ATL Other User",
"when" : ISODate("2019-04-19T15:31:39.912Z"),
"what" : "Name Change"
},
{
"version" : 1,
"who" : "ATL User",
"when" : ISODate("2019-04-19T15:30:39.912Z"),
"what" : "Item Creation"
}
]
}
可能需要一分钟才能理解为什么你会$push https://docs.mongodb.com/manual/reference/operator/update/push/为了$sort https://docs.mongodb.com/manual/reference/operator/update/sort/像这样的数组,但一般意图是当可能对数组进行修改时,“改变”属性,例如Date
值被排序,您将使用这样的语句来反映这些更改。或者实际上只是添加新项目$sort https://docs.mongodb.com/manual/reference/operator/update/sort/并让它解决。
So why "store"数组是这样排序的?正如前面提到的,你想要first项目作为“最近”,然后返回的查询就变成了:
db.items.find(
{
"subcategory": "Programming Languages",
"name": { "$exists": true }
},
{ "change": { "$slice": 1 } }
)
Returns:
{
"_id" : ObjectId("5cb9ea0c75c61525e0176f96"),
"value" : 1,
"name" : "Test",
"category" : "Development",
"subcategory" : "Programming Languages",
"status" : "Supported",
"description" : "Test",
"change" : [
{
"version" : 3,
"who" : "ATL User",
"when" : ISODate("2019-04-20T02:40:30.024Z"),
"what" : "Another change"
}
]
}
So the $slice https://docs.mongodb.com/manual/reference/operator/projection/slice/然后可以仅用于通过已知索引提取数组项。从技术上讲你可以使用-1
在那里为了返回last无论如何,数组的项目,但是首先重新排序最新的项目允许执行其他操作,例如确认最后一次修改是由某个用户进行的,和/或其他条件(例如日期范围约束)。 IE:
db.items.find(
{
"subcategory": "Programming Languages",
"name": { "$exists": true },
"change.0.who": "ATL User",
"change.0.when": { "$gt": new Date("2018-04-01") }
},
{ "change": { "$slice": 1 } }
)
在这里注意到类似的东西"change.-1.when"
是一个非法语句,这基本上就是我们重新排序数组的原因,以便您可以使用legal 0
for first代替-1
for last.
结论
因此,您可以执行多种不同的操作,可以使用聚合方法来过滤数组内容,也可以在对数据的实际存储方式进行一些修改后通过标准查询表单。使用哪一种取决于你自己的情况,但需要注意的是,任何一种标准查询表格将比通过聚合框架或任何计算运算符进行的任何操作运行得快得多。