如何计算 mongo 中参考集合的不同值
How to count distinct values of a reference collection in mongo
有一个指向作者列表的书籍列表,我想显示一棵树,在每个节点中都有作者姓名和他写的书的数量。最初,我将 authors[] 数组直接嵌入到 books 集合中,这非常有效,使用了聚合框架的魔力。然而,后来,我意识到为每个作者附上一些附加信息会很好(例如照片、传记数据、出生日期等)。对于第一个解决方案,这很糟糕,因为:
- 它复制了数据(没什么大不了的,是的,我知道 mongo 的目的是封装完整的对象,但我们暂时忽略它);
- 无论何时在旧记录上创建或更新额外的 属性 都不会受益于此更改,除非我专门查询一些独特的旧 属性 并使用更新所有图书作者new/updated 个值。
接下来是使用第二个集合,称为 authors,每个 books 文档都引用作者 ID 列表,像这样:
{
"_id" : ObjectId("58ed2a254374473fced950c1"),
"authors" : [
"58ed2a254d74s73fced950c1",
"58ed2a234374473fce3950c1"
],
"title" : "Book title"
....
}
为了获取作者的详细信息,我有两个选择:
- 进行额外的查询以从 author 集合中获取数据;
- 使用 DBRef。
问题:
- 使用 DBRefs 自动将作者数据加载到书籍对象中,类似于 JPA @MannyToOne 所做的事?
- 是否可以获取每个作者的著作数量,而不必查询每个作者的书籍数量?当作者被嵌入时,我能够汇总不同的作者姓名以及他出现的书籍文档的数量。两个集合之间可以这样查询吗?
对于实施此行为,您有何建议? (我正在使用 Spring 数据)
根据@Veeram 的建议,我能够编写此查询:
db.book_collection.aggregate([
{
$unwind: "$authorsIds"
},
{
$lookup: {
from: "authors_collection",
localField: "authorsIds",
foreignField: "_id",
as: "ref"
}
},
{$group: {_id: "$ref.authorName", count: {$sum: 1}}}
])
其中 returns 是这样的:
{
"_id" : [
"Paulo Coelho"
],
"count" : 1
}
/* 2 */
{
"_id" : [
"Jules Verne"
],
"count" : 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();
有一个指向作者列表的书籍列表,我想显示一棵树,在每个节点中都有作者姓名和他写的书的数量。最初,我将 authors[] 数组直接嵌入到 books 集合中,这非常有效,使用了聚合框架的魔力。然而,后来,我意识到为每个作者附上一些附加信息会很好(例如照片、传记数据、出生日期等)。对于第一个解决方案,这很糟糕,因为:
- 它复制了数据(没什么大不了的,是的,我知道 mongo 的目的是封装完整的对象,但我们暂时忽略它);
- 无论何时在旧记录上创建或更新额外的 属性 都不会受益于此更改,除非我专门查询一些独特的旧 属性 并使用更新所有图书作者new/updated 个值。
接下来是使用第二个集合,称为 authors,每个 books 文档都引用作者 ID 列表,像这样:
{
"_id" : ObjectId("58ed2a254374473fced950c1"),
"authors" : [
"58ed2a254d74s73fced950c1",
"58ed2a234374473fce3950c1"
],
"title" : "Book title"
....
}
为了获取作者的详细信息,我有两个选择:
- 进行额外的查询以从 author 集合中获取数据;
- 使用 DBRef。
问题:
- 使用 DBRefs 自动将作者数据加载到书籍对象中,类似于 JPA @MannyToOne 所做的事?
- 是否可以获取每个作者的著作数量,而不必查询每个作者的书籍数量?当作者被嵌入时,我能够汇总不同的作者姓名以及他出现的书籍文档的数量。两个集合之间可以这样查询吗?
对于实施此行为,您有何建议? (我正在使用 Spring 数据)
根据@Veeram 的建议,我能够编写此查询:
db.book_collection.aggregate([
{
$unwind: "$authorsIds"
},
{
$lookup: {
from: "authors_collection",
localField: "authorsIds",
foreignField: "_id",
as: "ref"
}
},
{$group: {_id: "$ref.authorName", count: {$sum: 1}}}
])
其中 returns 是这样的:
{
"_id" : [
"Paulo Coelho"
],
"count" : 1
}
/* 2 */
{
"_id" : [
"Jules Verne"
],
"count" : 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();