【发布时间】:2020-01-12 11:03:53
【问题描述】:
我是 Spring Data MongoDB 的新手,我正在尝试使用 Spring Data MongoDB 在 Java 中实现聚合查询。我已经尝试从这个问题中搜索并使用MongoTemplate 接近它,但仍然没有结果。
我的数据格式:
[{
"_id" : ObjectId("5e1aea6c275360baf96bac29"),
"title" : "postim",
"upvotesBy" : [
"5e18b4c12753608718dfa007",
"5e19ac0f5161a4994ded1f35"
],
"file" : "test",
"description" : "description",
"postedBy" : "5e18b4c12753608718dfa007",
"createdAt" : ISODate("2020-01-12T09:44:12.119+0000"),
"_class" : "com.socialnetwork.post.Post"
},
{
"_id" : ObjectId("5e1aeaf8275360bb4bb47325"),
"title" : "postim2",
"upvotesBy" : [
"5e18b4c12753608718dfa007",
"5e19ac0f5161a4994ded1f35"
],
"file" : "test2",
"description" : "description2",
"postedBy" : "5e18b4c12753608718dfa007",
"createdAt" : ISODate("2020-01-12T09:46:32.909+0000"),
"_class" : "com.socialnetwork.post.Post"
}]
我的查询:
db.post.aggregate([
{
$match: {}
},
{
$lookup: {
from: "users",
localField: "postedBy",
foreignField: "_id",
as: "user"
}
},
{
$group: {
_id: {
username: "$user.name",
title: "$title",
description: "$description",
upvotes: { $size: "$upvotesBy" },
upvotesBy: "$upvotesBy",
isUpvoted: { $in: [req.query.userId, "$upvotesBy"] },
isPinned: {
$cond: {
if: { $gte: [{ $size: "$upvotesBy" }, 3] },
then: true,
else: false
}
},
file: "$file",
createdAt: {
$dateToString: {
format: "%H:%M %d-%m-%Y",
timezone: "+01",
date: "$createdAt"
}
},
id: "$_id"
}
}
},
{ $sort: { "_id.isPinned": -1, "_id.createdAt": -1 } }
])
这是我在 Javascript 后端中使用的查询,我可以使用 Mongoose 轻松完成此操作。但是我对它的 Java 实现有一些困难。
private LookupOperation getLookupOperation() {
return LookupOperation.newLookup().from("user")
.localField("postedBy")
.foreignField("_id")
.as("user");
}
@Override
public List<PostSummary> aggregate() {
LookupOperation lookupOperation = getLookupOperation();
return mongoTemplate.aggregate(Aggregation.newAggregation(lookupOperation, Aggregation.group("id")
.addToSet("user.name").as("username")
.addToSet("title").as("title")
.addToSet("description").as("description")
.addToSet("id").as("id")
.push("upvotesBy").as("upvotesBy")
.addToSet("file").as("file")
.addToSet("createdAt").as("createdAt")
), Post.class, PostSummary.class).getMappedResults();
}
当我尝试运行它时,我收到以下错误:
"Cannot convert [] of type class java.util.ArrayList into an instance of class java.lang.Object! Implement a custom Converter<class java.util.ArrayList, class java.lang.Object> and register it with the CustomConversions. Parent object was: com.socialnetwork.post.PostSummary@7159d908"
当我从组聚合中删除 .addToSet("user.name").as("username") 时,我也收到来自 .push("upvotesBy").as("upvotesBy") 的错误,因为它无法转换 [] of type class java.util.ArrayList into an instance of class java.lang.String
Post 类和 PostSummary 类的实现也很简单:
Post.java:
@Document
public class Post {
@Id
private String id;
private String title;
private List<String> upvotesBy;
private String file;
private String description;
private String postedBy;
private Date createdAt = new Date();
// ... Getters and Setters for each field
}
PostSummary.java:
public class PostSummary {
private String username;
private String title;
private String description;
private List<String> upvotesBy;
private String file;
private String createdAt;
private String id;
//... Getters and Setters for the class
}
我还需要实现查询的isUpvoted 和isPinned 部分,但是了解如何解决第一个问题将是一个很好的开始。
编辑:我想要的输出:
[
{
"username" : "user1",
"title" : "postim2",
"upvotesBy" : [
"5e18b4c12753608718dfa007",
"5e19ac0f5161a4994ded1f35"
],
"file": "file1",
id: "5e18b4c12753608718dber01"
... Other fields of the original post
},
{
"username" : "user2",
"title" : "postim2",
"upvotesBy" : [
"5e18b4c12753608718dfa007",
"5e19ac0f5161a4994ded1f35"
],
id: "5e18b4c12753608718dber02",
"file": "file2",
... Other fields of the original post
}
]
所以从查找操作中我只需要获取用户名。
【问题讨论】:
-
你能发布 Spring-Data 版本吗?
-
问题是
$lookup返回数组,而不是单个用户文档。因此,您的聚合在$group阶段 (username: "$user.name") 失败。如果在$group阶段之前添加{"$unwind":"user"},它将起作用 -
@Valijon 我对
public List<PostSummary> aggregate()的尝试是 Spring-Data 版本,对吧? -
您是在开发 maven 项目吗?在这里发帖
pom.xml文件 -
@Valijon 这是一个 gradle 项目:
标签: java spring mongodb rest spring-data-mongodb