问题描述
{
"_id": "...","name": "name 1","created": "2020-07-21T08:11:18.414+00:00","tags": ["red","green"]
}
{
"_id": "...","name": "name 2","created": "2020-07-20T08:11:18.414+00:00","blue"]
}
{
"_id": "...","name": "name 3","created": "2020-07-19T08:11:18.414+00:00","tags": ["green","name": "name 4","created": "2020-07-18T08:11:18.414+00:00","tags": ["white","name": "name 5","created": "2020-07-17T08:11:18.414+00:00","green"]
}
我需要能够指定标签列表,并且对于列表中的每个标签,我都需要获取最新创建的文档。在上面的示例中,如果我指定["red","green","blue"]
,则应该得到类似于以下的结果:
{
"red": {
"_id": "...","green"]
},"green": {
"_id": "...","blue": {
"_id": "...","blue"]
}
}
我的问题是:
我对问题1的答案很满意,我可以分别寻找问题2的答案。
解决方法
如前所述,您可以通过聚合来实现
-
$sort
创建的按降序排列 -
$facet
有助于对内部文档进行分类,在其中我们使用$match
来过滤 tags -
$project
有助于投影。我们已经按创建的进行了排序。因此,我们将通过$arrayElemAt
获得第一个元素,有时,如果没有元素,它将引发异常,因此,为了返回空对象,我们使用$ifNull
Mongo脚本
[
{
$sort: {
created: -1
}
},{
$facet: {
red: [
{
$match: {
tags: "red"
}
}
],green: [
{
$match: {
tags: "green"
}
}
],blue: [
{
$match: {
tags: "blue"
}
}
]
}
},{
$project: {
red: {
$ifNull: [
{
"$arrayElemAt": [
"$red",0
]
},{}
]
},blue: {
$ifNull: [
{
"$arrayElemAt": [
"$blue",green: {
$ifNull: [
{
"$arrayElemAt": [
"$green",{}
]
}
}
}
]
当我们将其转换为Spring数据时
public List<Object> test() {
Aggregation aggregation = Aggregation.newAggregation(
sort(Sort.Direction.DESC,"created"),facet(
match(Criteria.where("tags").is("red"))
).as("red")
.and(
match(Criteria.where("tags").is("green"))
).as("green")
.and(
match(Criteria.where("tags").is("blue"))
).as("blue"),project()
.and(ConditionalOperators.ifNull(ArrayOperators.arrayOf("red").elementAt(0)).then(new Document())).as("red")
.and(ConditionalOperators.ifNull(ArrayOperators.arrayOf("blue").elementAt(0)).then(new Document())).as("blue")
.and(ConditionalOperators.ifNull(ArrayOperators.arrayOf("green").elementAt(0)).then(new Document())).as("green")
).withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());
return mongoTemplate.aggregate(aggregation,mongoTemplate.getCollectionName(YOUR_COLLECTION.class),Object.class).getMappedResults();
}
注意:我没有在spring-boot中测试以上代码。但是它是基于有效的mongo脚本编写的。希望它能工作。