在基于文档的聚合管道中使用 $merge 不起作用
Posted
技术标签:
【中文标题】在基于文档的聚合管道中使用 $merge 不起作用【英文标题】:Using $merge in Document-based aggregation pipeline is not working 【发布时间】:2021-11-29 22:40:29 【问题描述】:我有一个集合,我想对其执行聚合并将结果放入同一数据库中的单独集合中。在仔细检查文档时,我偶然发现了$merge
,它完全符合我的要求。我想出了以下 mongo shell 管道,它可以完美运行。
db.getCollection('SOURCE_COLLECTION').aggregate([
"$match": type: 'ABC'
,
"$merge":
"into": "OUTPUT_COLLECTION",
"whenMatched": "replace"
])
现在,我需要在 Spring boot 中实现同样的效果,为此我想出了以下方法,理论上应该没有什么不同。
final ArrayList<Document> pipeline = new ArrayList<>();
pipeline.add(Document.parse("$match: type: 'ABC'"));
pipeline.add(Document.parse("$merge: into: 'OUTPUT_COLLECTION', whenMatched: 'replace'"));
mongoTemplate.getDb()
.getCollection("SOURCE_COLLECTTION", Document.class)
.aggregate(pipeline);
不过,这行不通。可以看出,我正在使用MongoCollection<T>.aggregate()
方法,它将List<Document>
作为管道。管道中的每个阶段都是通过将 JSON 字符串解析为文档来生成的。
有趣的是,当我将合并替换为 $out
时,它可以正常工作。
final ArrayList<Document> pipeline = new ArrayList<>();
pipeline.add(Document.parse("$match: type: 'ABC'"));
pipeline.add(Document.parse("$out: 'OUTPUT_COLLECTION'"));
mongoTemplate.getDb()
.getCollection("SOURCE_COLLECTTION", Document.class)
.aggregate(pipeline);
但这对我没有好处,因为这个聚合将被执行多次(实际上我试图在这里填充一个物化视图类型的集合)。我需要$merge
才能工作,但它不需要。我错过了什么?有人能看到我没有看到的东西吗?
【问题讨论】:
【参考方案1】:当在管道中使用$merge
时,方法aggregate(pipeline)
的行为看起来不像终端操作。为了使合并工作,应该调用一些像void toCollection()
或void forEach(Consumer<? extends T> consumer)
这样的操作。因此,在从 aggregate()
返回时调用 toCollection()
就可以了。
final ArrayList<Document> pipeline = new ArrayList<>();
pipeline.add(Document.parse("$match: type: 'ABC'"));
pipeline.add(Document.parse("$out: 'OUTPUT_COLLECTION'"));
mongoTemplate.getDb()
.getCollection("SOURCE_COLLECTTION", Document.class)
.aggregate(pipeline)
.toCollection(); // This invocation completes the pipeline when it ends with $merge.
有趣的是,在文件中似乎没有提到这种类型(至少在我能找到的任何文件中都没有)。我不确定这是否是预期的行为。
【讨论】:
以上是关于在基于文档的聚合管道中使用 $merge 不起作用的主要内容,如果未能解决你的问题,请参考以下文章