如何计算mongo中引用集合的不同值

时间:2017-04-15 10:44:13

标签: java mongodb aggregation-framework spring-data-mongodb dbref

有一个指向作者列表的书籍列表,我想要显示一个树,在每个节点中都有作者姓名和他写的书数。最初,我已将 authors [] 数组直接嵌入到 books 集合中,这就像一个魅力,使用聚合框架的魔力。然而,稍后,我意识到每个作者附加一些附加信息会很好(例如它的图片,传记数据,出生日期等)。对于第一个解决方案,这很糟糕,因为:

  • 它复制数据(不是很重要,是的,我知道mongo的目的是封装完整的对象,但是现在让我们忽略它);
  • 每当在旧记录上创建或更新其他属性都不会从此更改中受益,除非我专门查询某些唯一的旧属性并使用新的/更新的值更新所有图书作者。

接下来要使用名为 authors 的第二个集合,每个图书文档都引用了一个作者ID列表,如下所示:

{
    "_id" : ObjectId("58ed2a254374473fced950c1"),
    "authors" : [ 
        "58ed2a254d74s73fced950c1", 
        "58ed2a234374473fce3950c1"
    ],
    "title" : "Book title"
....
}

为了获得作者的详细信息,我有两个选择:

  • 进行其他查询以从作家集合中获取数据;
  • 使用DBRefs。

问题:

  1. 使用DBRefs会自动将作者数据加载到book对象中,类似于JPA @MannyToOne所做的那样吗?
  2. 是否有可能获得每位作者的书面书籍数量,而无需查询每位作者的书籍数量?当作者被嵌入时,我能够聚合不同的作者姓名以及他出现的书籍文件的数量。两个集合之间是否可以进行此类查询?
  3. 您对实施此行为的建议是什么? (我正在使用Spring Data)

2 个答案:

答案 0 :(得分:2)

您可以在spring mongo应用程序中尝试以下查询。

UnwindOperation unwindAuthorIds = Aggregation.unwind("authorsIds", true);
LookupOperation lookupAuthor = Aggregation.lookup("authors_collection", "authorsIds", "_id", "ref");
UnwindOperation unwindRefs = Aggregation.unwind("ref", true);
GroupOperation groupByAuthor = Aggregation.group("ref.authorName").count().as("count");

Aggregation aggregation = Aggregation.newAggregation(unwindAuthorIds, lookupAuthor, unwindRefs, groupByAuthor);

List<BasicDBObject> results = mongoOperations.aggregate(aggregation, "book_collection", BasicDBObject.class).getMappedResults();

答案 1 :(得分:1)

按照@ Veeram的建议,我能够写下这个查询:

db.book_collection.aggregate([
    {
        $unwind: "$authorsIds"
    },
    {
        $lookup: {
            from: "authors_collection",
            localField: "authorsIds",
            foreignField: "_id",
            as: "ref"
        }
    },
    {$group: {_id: "$ref.authorName", count: {$sum: 1}}}
])

返回如下内容:

{
    "_id" : [ 
        "Paulo Coelho"
    ],
    "count" : 1
}

/* 2 */
{
    "_id" : [ 
        "Jules Verne"
    ],
    "count" : 2
}

这正是我所需要的,听起来是正确的。我现在只需要做一个额外的查询来获取没有作者设置的书籍。