You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中如何按点路径查询MongoDB嵌套JSON指定字段值

问题场景

我有一个存储不同厂商网络设备详情的MongoDB数据库,库中存储的数据结构示例如下:

{
  "data": [
    {
      "_id": "00259E-HG8145V5-435754432197F5E3",
      "ModelName": {
        "_object": false,
        "_timestamp": {
          "milliseconds": "1652710497483"
        },
        "_type": "xsd:string",
        "_value": "HG8145V5",
        "_writable": false
      },
      "InternetGatewayDevice": {
        "ManagementServer": {
          "ConnectionRequestPassword": {
            "_object": false,
            "_timestamp": {
              "milliseconds": "1652862119046"
            },
            "_type": "xsd:string",
            "_value": "2blvl18wlqy",
            "_writable": true
          },
          "ConnectionRequestURL": {
            "_object": false,
            "_timestamp": {
              "milliseconds": "1652871839678"
            },
            "_type": "xsd:string",
            "_value": "http://10.35.170.34:7547/697bce9e70e191842ee5a8272c0e7f21",
            "_writable": true
          }
        }
      }
    }
  ]
}

当用户传入点分隔的查询路径时,例如:

InternetGatewayDevice.ManagementServer.ConnectionRequestURL

需要返回对应路径下的目标值,示例返回结果如下:

http://10.35.170.34:7547/697bce9e70e191842ee5a8272c0e7f21

需求为在Laravel框架中遍历该类嵌套JSON/数组结构,精准匹配请求路径返回对应字段值。


实现方案

该存储结构有固定特征:所有叶子节点的实际业务值都存在_value字段下,路径匹配按点拆分后逐层向下查找即可,无需额外依赖第三方包,直接使用Laravel自带的数组工具类就能实现。

核心逻辑

  • 从MongoDB取出设备数据后统一转为数组格式,避免对象属性访问的兼容问题
  • 将用户传入的点分隔路径拆分为分段数组,逐层遍历查找
  • 每定位到一层节点就判断节点类型:如果是叶子节点(存在_value字段)直接返回实际值,如果是嵌套结构就继续向下遍历
  • 路径不存在时返回预设默认值,或根据业务需要抛出对应异常

可直接复用的代码

可以将逻辑封装为自定义辅助函数,或者挂载到模型方法中:

<?php

use Illuminate\Support\Arr;

/**
 * 根据点分隔路径获取设备存储结构中的目标值
 * @param array $deviceData 从MongoDB查询到的单条设备数据数组
 * @param string $path 点分隔的查询路径
 * @param mixed $default 路径不存在时返回的默认值
 * @return mixed
 */
function getDeviceFieldValue(array $deviceData, string $path, mixed $default = null)
{
    // 拆分路径为独立分段
    $pathSegments = explode('.', $path);
    $currentNode = $deviceData;

    foreach ($pathSegments as $segment) {
        // 当前节点不存在对应字段,直接返回默认值
        if (!is_array($currentNode) || !Arr::exists($currentNode, $segment)) {
            return $default;
        }
        $currentNode = $currentNode[$segment];
    }

    // 遍历到路径终点后,优先返回标准叶子节点的_value值
    if (is_array($currentNode) && Arr::exists($currentNode, '_value')) {
        return $currentNode['_value'];
    }

    // 如果终点是_object为true的嵌套结构,直接返回整个节点
    return $currentNode ?? $default;
}

控制器调用示例

<?php

namespace App\Http\Controllers;

use App\Models\NetworkDevice;
use Illuminate\Http\Request;

class DeviceQueryController extends Controller
{
    public function getField(Request $request)
    {
        $request->validate([
            'device_id' => 'required|string',
            'field_path' => 'required|string',
        ]);

        // 查询对应设备,使用jenssegers/mongodb扩展时可直接调用toArray转数组
        $device = NetworkDevice::find($request->input('device_id'));
        if (!$device) {
            return response()->json(['message' => '设备不存在'], 404);
        }

        $value = getDeviceFieldValue($device->toArray(), $request->input('field_path'));
        
        return response()->json([
            'code' => 0,
            'data' => $value
        ]);
    }
}

注意事项

  • 示例中写的查询路径InternetGatewayDevice.ManagementServer.URL和实际存储字段ConnectionRequestURL不匹配,传入路径需要和存储字段名完全一致,且大小写敏感
  • 如果业务需要支持模糊匹配(比如输入URL自动匹配到ConnectionRequestURL),可以在每层遍历的时候加str_contains字段名判断,但生产环境不建议使用,容易出现多字段匹配歧义
  • 时间戳、字段类型、可写状态等元数据如果需要返回,直接去掉叶子节点取_value的逻辑即可返回完整节点内容

内容的提问来源于stack exchange,提问作者ahmad blat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 23:27:29