MongoDB+PHP查询:根据path字段获取指定子文档数据
MongoDB + PHP:按path筛选translations子文档并合并父字段
先看示例文档结构,假设你的集合里的文档长这样:
{ "_id": ObjectId("60d21b4667d0d8992e610c85"), "title": "基础文档标题", "category": "教程", "translations": [ { "path": "content-english.html", "content": "Hello World", "lang": "en" }, { "path": "content-chinese.html", "content": "你好世界", "lang": "zh" } ] }
当你搜索content-english.html时,期望得到的结果是父文档基础字段和匹配的子文档字段合并后的结构:
{ "_id": ObjectId("60d21b4667d0d8992e610c85"), "title": "基础文档标题", "category": "教程", "path": "content-english.html", "content": "Hello World", "lang": "en" }
解决方案:用MongoDB聚合框架实现
直接用PHP的MongoDB驱动编写聚合管道,分四步处理:
- 先过滤出包含目标path的文档,减少后续处理数据量
- 展开
translations数组,把每个子文档单独成一个文档 - 筛选出path完全匹配的文档
- 合并父文档基础字段和子文档字段,替换为新的根文档
完整PHP代码如下:
<?php require 'vendor/autoload.php'; // 连接MongoDB $client = new MongoDB\Client("mongodb://localhost:27017"); // 指定集合(替换成你的库名和集合名) $collection = $client->your_db_name->your_collection_name; // 要搜索的目标path $targetPath = 'content-english.html'; // 构建聚合管道 $pipeline = [ // 第一步:筛选包含目标path的文档 ['$match' => [ 'translations.path' => $targetPath ]], // 第二步:展开translations数组 ['$unwind' => '$translations'], // 第三步:精准匹配path的子文档 ['$match' => [ 'translations.path' => $targetPath ]], // 第四步:合并父字段与子文档字段,生成最终结构 ['$replaceRoot' => [ 'newRoot' => [ '$mergeObjects' => [ // 手动指定要保留的父文档基础字段 ['_id' => '$_id', 'title' => '$title', 'category' => '$category'], // 合并子文档的所有字段 '$translations' ] ] ]] ]; // 执行聚合查询 $result = $collection->aggregate($pipeline); // 遍历输出结果 foreach ($result as $doc) { echo json_encode($doc, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n"; } ?>
优化:自动保留所有父字段(无需手动列举)
如果父文档的基础字段较多,不想逐个写,可以用下面的管道替换原第四步,自动排除translations字段后合并:
// 替换原第四步的内容 ['$project' => [ 'translations' => 1, // 提取父文档所有字段,排除translations 'parentFields' => ['$mergeObjects' => ['$$ROOT', ['translations' => '$$REMOVE']]] ]], ['$replaceRoot' => [ 'newRoot' => ['$mergeObjects' => ['$parentFields', '$translations']] ]]
这样不管父文档有多少字段,都会自动保留并和子文档字段合并。
内容的提问来源于stack exchange,提问作者Jonathan A
相关产品推荐
相关产品推荐

