【问题标题】:Spring MongoDB: Projecting Array field size if it existsSpring MongoDB:投影数组字段大小(如果存在)
【发布时间】:2020-04-20 20:34:55
【问题描述】:

我的文档中有一个数组字段replies,它可能存在也可能不存在。如果存在,我想返回它的大小,否则返回 0。下面是我的投影代码。对于包含 replies 字段和元素的文档,它返回 0。

 ProjectionOperation project = Aggregation.project("title", "datePosted", "likes").
        and(ConditionalOperators.ifNull(ArrayOperators.arrayOf("replies").length()).then(0)).as("repliesCount");

阅读 MongoDB 参考资料doc,这很简单,但不知何故它不起作用。

欢迎提出任何建议。

样本数据

{
"_id" : ObjectId("5e9e3873d022d154c54c2969"),
"title" : "Is this a nice place to meet some interesting people?",
"datePosted" : ISODate("2020-04-21T00:04:03.731Z"),
"views" : 0,
"likes" : 0,
"active" : true
},
{
"_id" : ObjectId("5e9e2f37d022d154c54c2961"),
"title" : "I am posting a quick discussion",
"datePosted" : ISODate("2020-04-20T23:24:39.768Z"),
"views" : 120,
"likes" : 4,
"active" : true,
"replies" : [ 
    {
        "_id" : ObjectId("5e9e2f69d022d154c54c2963"),
        "reply" : "This is the first reply",
        "datePosted" : ISODate("2020-04-20T23:25:29.608Z"),
        "likes" : 0
    },
    {
        "_id" : ObjectId("5e9e2f69d022ad4c54c2964"),
        "reply" : "This is another reply",
        "datePosted" : ISODate("2020-04-20T23:25:29.608Z"),
        "likes" : 0
    }
]
}

根本原因

@valijon 提供的解决方案是正确的。问题出在结果映射到的 POJO DiscussionDoc 上。

@Document(collection = "discussions")
public class DiscussionDoc {

  @Id
  private ObjectId id;

  private String title;
  private LocalDateTime datePosted;
  private int views;
  private int likes;

  @Transient
  private int repliesCount;
  private boolean active;

  @Field(value = "replies")
  private List<ReplyDoc> replyList;
}

删除@Transient 即可。我在repliesCount 上使用@Transient,因为我不想在持久化DiscussionDoc 时持久化这个字段。坚持这个领域没有任何用处。但在获取DiscussionDoc 时,它将用于保存总回复计数。但是@Transient 在获取DiscussionDoc 时以某种方式不允许设置repliesCount。我已删除 @Transient 以解决此问题。但是,repliesCount 字段现在保存在 DB 中该怎么办?

【问题讨论】:

标签: spring mongodb spring-boot spring-data


【解决方案1】:

你几乎接近了:

ProjectionOperation project = Aggregation.project("title", "datePosted", "likes").
    and(ArrayOperators.arrayOf(ConditionalOperators.ifNull("replies").then(Collections.emptyList())).length()).as("repliesCount");

相当于:

{
  "$project": {
    "title": 1,
    "datePosted": 1,
    "likes": 1,
    "repliesCount": {
      "$size": {
        "$ifNull": [
          "$replies",
          []
        ]
      }
    }
  }
}

解决方法:您可以使用Gson 序列化程序来获取此计算值:

private static final Gson g = new GsonBuilder().create();
...

List<Document> result = mongoTemplate.aggregate(aggregation, 
    mongoTemplate.getCollectionName(DiscussionDoc.class), Document.class)
        .getMappedResults();

return result.stream()
    .map(doc -> g.fromJson(doc.toJson(), DiscussionDoc.class))
    .collect(Collectors.toList());

【讨论】:

  • 我明白你做了什么。但它仍然返回repliesCount 0。
  • @MeenaChaudhary 请分享您的样本数据
  • 向问题添加了示例数据。
  • @MeenaChaudhary 它按预期工作mongoplayground.net/p/x3Mt48b2w8P。也许您正在运行 TypedAggregation?
  • 不,我正在使用常规聚合。
猜你喜欢
  • 1970-01-01
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多