获取按集合属性长度排序的 MongoDB 文档列表 - Spring Boot
因此,我在 MongoDB 中有一个存储库,其中包含具有以下结构的电影:
title: String
description: String
likes: Set<String>
hates: Set<String>
likes
& hates
是一个 Set
,因为它们包含一个 UserIds
列表 - 其中具有这些 UserIds
的用户就是那些喜欢/讨厌这部电影。
我试图让我的服务从数据库中获取所有电影,按喜欢/讨厌的数量排序。以前,我的结构不同,喜欢
/讨厌
只是Integer
。然后,获取所有排序的电影就很容易了:
public List<MovieDocument> getSortedMovies(SortProperty sortBy, Order order) {
return moviesRepository.findAll(Sort.by(fromString(order.toString()), sortBy.toString()))
}
其中 sortBy
是 likes
或 hates
,而 order
是 >asc
或 desc
,由 API 客户端提供。
在上述情况下,MoviesRepository
没有任何自定义方法:
@Repository
public interface MoviesRepository extends MongoRepository<MovieDocument, String> {}
既然 likes
和 hates
都是 ,我该怎么做? >设置
对象?
同样,我想要的是让所有电影按喜欢/讨厌集的大小排序。
- 我可以使用任何内置的
MongoRepository
方法来做到这一点吗?我看了一下,没有看到任何有用的东西。 - 查看其他 StackOverflow 帖子,我发现有一个选项可以使用
Aggregation
注释向我的MoviesRepository
添加方法。这看起来像:
@Aggregation("{$project: { 'like_count': { $size: '$likes' } }}, {$sort: {'like_count': -1}}]")
List<String> getSortedMovieIdsByLikesDesc();
但是,这不会返回整个 MovieDocument
,而是返回喜欢的数量。除此之外,看起来我必须为每个属性/顺序组合创建一个新的自定义方法,即 likes-asc、likes-desc、hates-asc、hates-desc。这感觉很乏味并且可扩展性不太好。
我将如何解决上述问题以返回整个文档,还有其他我没有考虑的方法吗?
编辑
我根据@rickhg12hs的输入尝试了以下操作。
@Aggregation("{$set: { like_count: { $size: $likes } }}, {$sort: {like_count: -1}}")
List<MovieDocument> getSortedMovieIdsByLikesDesc();
@Aggregation("{$set: { like_count: { $size: $likes } }}, {$sort: {like_count: 1}}")
List<MovieDocument> getSortedMovieIdsByLikesAsc();
@Aggregation("{$set: { hate_count: { $size: $hates } }}, {$sort: {hate_count: -1}}")
List<MovieDocument> getSortedMovieIdsByHatesDesc();
@Aggregation("{$set: { hate_count: { $size: $hates } }}, {$sort: {hate_count: 1}}")
List<MovieDocument> getSortedMovieIdsByHatesAsc();
不幸的是,所有这四个方法在调用时似乎都返回完全相同的内容。具体来说,它们返回数据库中无序的两个项目。
So, I have this repository in MongoDB that holds movies with this structure:
title: String
description: String
likes: Set<String>
hates: Set<String>
The likes
& hates
are a Set
because they hold a list of UserIds
- where the user with those UserIds
are the ones that liked/hated the movie.
I am trying to have my service get all movies from the database, sorted by the number of likes/hates. Previously, my structure was different, and likes
/hates
were just Integer
s. Then, getting all sorted movies was easy:
public List<MovieDocument> getSortedMovies(SortProperty sortBy, Order order) {
return moviesRepository.findAll(Sort.by(fromString(order.toString()), sortBy.toString()))
}
Where sortBy
was either likes
or hates
and order
was either asc
or desc
, provided by the client of the API.
In the above case, MoviesRepository
didn't have any custom methods:
@Repository
public interface MoviesRepository extends MongoRepository<MovieDocument, String> {}
How am I supposed to do that now that likes
and hates
are Set
objects?
Again, what I want is to get all movies sorted by the size of the likes
/hates
sets.
- Can I do that using any of the built-in
MongoRepository
methods? I had a look and didn't see anything useful. - Looking at other StackOverflow posts, I saw there is an option to add methods to my
MoviesRepository
with anAggregation
annotation. This would look something like:
@Aggregation("{$project: { 'like_count': { $size: '$likes' } }}, {$sort: {'like_count': -1}}]")
List<String> getSortedMovieIdsByLikesDesc();
However, this does not return the whole MovieDocument
, but rather it returns the number of likes. In addition to that, it looks like I'd have to create a new custom method for each property/order combination i.e. likes-asc, likes-desc, hates-asc, hates-desc. This feels tedious and not very extensible.
How would I fix the above to return whole documents and is there any other way to do this I'm not considering?
EDIT
I tried the following based on input from @rickhg12hs.
@Aggregation("{$set: { like_count: { $size: $likes } }}, {$sort: {like_count: -1}}")
List<MovieDocument> getSortedMovieIdsByLikesDesc();
@Aggregation("{$set: { like_count: { $size: $likes } }}, {$sort: {like_count: 1}}")
List<MovieDocument> getSortedMovieIdsByLikesAsc();
@Aggregation("{$set: { hate_count: { $size: $hates } }}, {$sort: {hate_count: -1}}")
List<MovieDocument> getSortedMovieIdsByHatesDesc();
@Aggregation("{$set: { hate_count: { $size: $hates } }}, {$sort: {hate_count: 1}}")
List<MovieDocument> getSortedMovieIdsByHatesAsc();
Unfortunately, all four of those methods seem to return the exact same thing when called. Specifically they return the two items that are in the database unordered.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你似乎几乎所有事情都做对了。这是一个我认为你想要的例子。
如果您也想删除计数,可以取消注释
"$project"
阶段。在 mongoplayground.net 上尝试一下。
You seem to be doing almost everything right. Here's an example that does what I think you want.
You can uncomment the
"$project"
stage if you want to remove the counts too.Try it on mongoplayground.net.