将含$lookup与$unionWith的MongoDB聚合查询转换为Elasticsearch查询咨询
MongoDB聚合查询转Elasticsearch实现方案
你提供的MongoDB聚合查询实际完成三个操作:
- 查parent集合的所有文档,左关联child集合中
parent_id匹配的文档,关联结果存入items字段 - 将上述关联后的parent结果,和child集合中
channel_id=1的所有原生文档做并集合并 - 最终所有合并结果按
created_at倒序排序
Elasticsearch可按两种场景实现完全相同的返回结果:
场景1:可调整索引结构(推荐,单次查询即可完成)
如果可以给两个索引配置父子关联关系,首先给parent索引新增join类型字段:
PUT /parent/_mapping { "properties": { "join_field": { "type": "join", "relations": { "parent": "child" } } } }
之后给child索引的每个文档补充join_field字段,值为{"name": "child", "parent": "<对应parent_id值>"},同时设置child索引的routing值为对应parent_id。
配置完成后可直接用以下DSL查询得到目标结果:
GET /parent,child/_search { "query": { "bool": { "should": [ // 匹配所有parent索引文档,同时拉取关联的child数据 { "bool": { "must": [ {"term": {"_index": "parent"}}, { "has_child": { "type": "child", "inner_hits": {"name": "items"}, "query": {"match_all": {}} } } ] } }, // 匹配child索引中channel_id=1的原生文档 { "bool": { "must": [ {"term": {"_index": "child"}}, {"term": {"channel_id": 1}} ] } } ] } }, "sort": [ {"created_at": {"order": "desc"}} ] }
查询结果中parent文档的inner_hits.items就是关联的child数组,将该字段重命名为items即可和原Mongo返回结构完全一致。
场景2:不可修改索引结构
如果无法调整索引配置,可通过两次查询实现相同结果:
- 第一次查询拿到所有符合条件的基础文档列表:
GET /parent,child/_search { "query": { "bool": { "should": [ {"term": {"_index": "parent"}}, { "bool": { "must": [ {"term": {"_index": "child"}}, {"term": {"channel_id": 1}} ] } } ] } }, "sort": [{"created_at": {"order": "desc"}}], "size": 1000 // 按实际需要的返回条数调整 }
- 从第一次返回结果中提取所有parent文档的
parent_id值,组成数组parent_id_list,第二次查询child索引拿到所有需要关联的child文档:
GET /child/_search { "query": { "terms": {"parent_id": parent_id_list} }, "size": 10000 // 调整到足够覆盖所有关联child即可 }
- 代码层面把查询到的child文档按
parent_id分组,填充到对应parent文档的items字段,最终结果和原Mongo返回完全一致。
内容的提问来源于stack exchange,提问作者teguh11
相关产品推荐
相关产品推荐

