如何用Node.js MongoDB驱动合并多集合并筛选含视频的媒体条目
多集合并联筛选实现方案
针对跨集合合并的需求,使用MongoDB 4.3.1及以上版本支持的$unionWith聚合阶段实现,无需多次查询后在应用层合并,可直接在数据库层面完成去重、字段整理和合并操作。
整体处理逻辑
- 拆分4个独立预处理分支,分别处理不同来源的符合条件数据
- 统一通过
$filter提取media_urls中的视频链接,避免直接$unwind拆分数组产生重复 - 每个分支预处理完成后再通过
$unionWith合并,输出结构统一不会混乱
各分支处理规则
- Business嵌套商品分支(type=products)
- 先对Business集合的
products数组执行$unwind,拆分每个商品为独立条目 - 用正则匹配商品的
media_urls中是否存在视频文件 - 保留商品自身的
_id、name、lower_price、higher_price、description字段,标注type为products - 用
$filter过滤出media_urls中的视频链接
- 先对Business集合的
- Business主体媒体分支(type=business)
- 直接匹配Business集合自身的
media_urls中是否存在视频文件 - 仅保留Business的
_id字段,标注type为business - 用
$filter过滤出自身media_urls中的视频链接
- 直接匹配Business集合自身的
- Offer集合分支(type=offer)
- 匹配Offer集合自身
media_urls含视频的条目 - 保留Offer的
_id、name、lower_price、higher_price、description字段,标注type为offer - 用
$filter过滤出media_urls中的视频链接
- 匹配Offer集合自身
- Product Request集合分支(type=request)
- 匹配Product Request集合自身
media_urls含视频的条目 - 保留Request的
_id、name、lower_price、higher_price、description字段,标注type为request - 用
$filter过滤出media_urls中的视频链接
- 匹配Product Request集合自身
完整聚合示例代码
// 先处理Business集合的两个分支,再依次合并其他集合 db.Business.aggregate([ // 第一阶段:先处理Business嵌套的商品条目 { $unwind: "$products" }, // 筛选商品媒体含视频的条目 { $match: { "products.media_urls": { $regex: /\.(mp4|mov|avi)$/i } } }, // 整理为统一输出结构 { $project: { _id: "$products._id", type: { $literal: "products" }, name: "$products.name", lower_price: "$products.lower_price", higher_price: "$products.higher_price", description: "$products.description", // 仅保留视频链接 media_urls: { $filter: { input: "$products.media_urls", as: "url", cond: { $regexMatch: { input: "$$url", regex: /\.(mp4|mov|avi)$/i } } } } } }, // 合并Business主体媒体的处理结果 { $unionWith: { coll: "Business", pipeline: [ // 筛选Business自身媒体含视频的条目 { $match: { media_urls: { $regex: /\.(mp4|mov|avi)$/i } } }, { $project: { _id: 1, type: { $literal: "business" }, media_urls: { $filter: { input: "$media_urls", as: "url", cond: { $regexMatch: { input: "$$url", regex: /\.(mp4|mov|avi)$/i } } } } } } ] } }, // 合并Offer集合的处理结果 { $unionWith: { coll: "Offer", pipeline: [ { $match: { media_urls: { $regex: /\.(mp4|mov|avi)$/i } } }, { $project: { _id: 1, type: { $literal: "offer" }, name: 1, lower_price: 1, higher_price: 1, description: 1, media_urls: { $filter: { input: "$media_urls", as: "url", cond: { $regexMatch: { input: "$$url", regex: /\.(mp4|mov|avi)$/i } } } } } } ] } }, // 合并Product Request集合的处理结果 { $unionWith: { coll: "Product Request", pipeline: [ { $match: { media_urls: { $regex: /\.(mp4|mov|avi)$/i } } }, { $project: { _id: 1, type: { $literal: "request" }, name: 1, lower_price: 1, higher_price: 1, description: 1, media_urls: { $filter: { input: "$media_urls", as: "url", cond: { $regexMatch: { input: "$$url", regex: /\.(mp4|mov|avi)$/i } } } } } } ] } } ])
注意事项
- 本方案中的
$unwind仅用于拆分Business集合嵌套的products数组,不会拆分media_urls字段,所有视频链接会统一保留在同一条结果的数组中,不会产生重复条目 - 正则规则可根据实际业务的视频后缀调整,无需额外匹配图片格式
- 若需要对合并后的结果按
type或其他字段排序,可在最后追加$sort阶段 - 若MongoDB版本低于4.3.1,可先分别对3个集合执行独立聚合查询,在应用层手动合并结果,注意提前对嵌套数组做
$filter处理避免重复数据
内容的提问来源于stack exchange,提问作者Joyner
相关产品推荐
相关产品推荐

