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

如何在Mongoose中实现value字段内嵌套对象与字符串的统一搜索

MongoDB嵌套对象字段搜索问题

数据结构

我的数据库中有两类数据:

{
    "name": "Description",
    "value": "Lorem ipsum"
}

{
    "name": "Properties",
    "value": {
        "type": "Big house",
        "address": "21 Main street",
        "city": "New York"
    }
}

需求

需要实现搜索功能,匹配value字段内的任意内容:

  • 搜索'Description'中包含'Lorem'(正常工作)
  • 搜索'Properties'中包含'Big'(无法工作)
  • 搜索'Properties'中包含'type'(无法工作)
  • 搜索'Properties'中包含'address'(无法工作)

当前问题

搜索仅能匹配value为字符串时的内容,当value为嵌套对象时无结果返回。需要让Mongo将value对象视为字符串进行搜索,例如搜索'type'或'house'时能筛选出'Properties'对象。

现有Mongoose聚合代码

{
    $group: {
        _id: "$_id",
        key: { $first: "$key" },
        fields: {
            $push: {
                "k": "$fields.name",
                "v": "$fields.value"
            }
        }
    },
},
{
    $match: {
        [filter.name]: {
            $regex: filter.value || '',
        }
    }
}

编辑补充

使用Charchit Kapoor提供的解决方案后,出现Feature not supported错误,错误信息如下:

[Nest] 150067  - 05/12/2023, 1:50:53 PM   ERROR [ExceptionsHandler] Feature not supported
MongoServerError: Feature not supported
    at Connection.onMessage (/node_modules/mongodb/src/cmap/connection.ts:438:20)
    at MessageStream.<anonymous> (/node_modules/mongodb/src/cmap/connection.ts:256:56)
    at MessageStream.emit (events.js:376:20)
    at MessageStream.emit (domain.js:532:15)
    at processIncomingData (/node_modules/mongodb/src/cmap/message_stream.ts:193:14)
    at MessageStream._write (/node_modules/mongodb/src/cmap/message_stream.ts:70:5)
    at writeOrBuffer (internal/streams/writable.js:358:12)
    at MessageStream.Writable.write (internal/streams/writable.js:303:10)
    at TLSSocket.ondata (internal/streams/readable.js:745:22)
    at TLSSocket.emit (events.js:376:20)

当前尝试的代码:

{
    $match: {
      name: filter.name,
      $expr: {
        $regexMatch: {
          input: {
             $function: {
                body: "function (doc) { return JSON.stringify(doc); }",
                args: [
                  "$value"
                ],
                lang: "js"
             }
          },
          regex: "ips"
       }
     }
   }
}

解决方案

方案1:用原生聚合操作符转换嵌套对象(兼容多数版本)

如果你的MongoDB版本不支持$function,或者环境限制了JS函数,可以用原生操作符把嵌套对象转为字符串:

{
  $addFields: {
    valueAsString: {
      $reduce: {
        input: { $objectToArray: "$value" },
        initialValue: "",
        in: {
          $concat: [
            "$$value",
            "$$this.k",
            ":",
            { $cond: [{ $isString: "$$this.v" }, "$$this.v", { $toString: "$$this.v" }] },
            ", "
          ]
        }
      }
    }
  }
},
{
  $match: {
    valueAsString: { $regex: filter.value || '', $options: 'i' } // 可选i参数忽略大小写
  }
}

这个方法会把value的键值对拼接成字符串,比如Properties的value会转为type:Big house, address:21 Main street, city:New York, ,这样就能匹配键(如type)或值(如Big)。

方案2:启用JS函数支持(MongoDB 4.4+)

如果环境支持$function但报错,可能是部署配置限制,检查实例权限后可以用更简洁的写法:

{
  $match: {
    $expr: {
      $regexMatch: {
        input: {
          $function: {
            body: (doc) => JSON.stringify(doc),
            args: ["$value"],
            lang: "js"
          }
        },
        regex: filter.value || '',
        options: 'i'
      }
    }
  }
}

方案3:预存字符串化字段

如果聚合转换性能不足,可以在数据插入/更新时,同步存储一个valueString字段,直接存JSON.stringify(value)的结果:

// 插入数据时
await Model.create({
  name: "Properties",
  value: { type: "Big house", address: "21 Main street", city: "New York" },
  valueString: JSON.stringify({ type: "Big house", address: "21 Main street", city: "New York" })
});

// 查询时
{
  $match: {
    valueString: { $regex: filter.value || '', $options: 'i' }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:27:07