如何使用Mongoose查询MongoDB中匹配指定值的数组对应的字段名
我来帮你解决这个问题!你当前的查询存在两个关键问题:一是$query并不是MongoDB的合法查询操作符,二是默认的find方法只会返回匹配的整个文档,没办法直接提取出目标值所在的字段名。下面给你两种可行的解决方案,你可以根据实际场景选择:
方案一:使用MongoDB聚合管道(适合字段不固定或数量较多的场景)
这种方法利用MongoDB的聚合框架,直接在数据库层面完成字段的筛选和提取,不需要在代码里做太多遍历操作:
const mongoose = require("mongoose"); const listSchema = new mongoose.Schema({ yuck: [String], yumm: [String] }); const List = mongoose.model("List", listSchema); // 先确保文档已创建(如果已存在可以跳过这步) List.create({ yuck: ["orange", "banana"], yumm: ["broccoli", "chocolate"] }) .then(() => { // 执行聚合查询 return List.aggregate([ // 第一步:匹配包含目标值"chocolate"的文档 { $match: { $or: [{ yuck: "chocolate" }, { yumm: "chocolate" }] } }, // 第二步:把文档转为键值对数组(排除_id字段) { $project: { data: { $objectToArray: "$$ROOT" }, _id: 0 } }, // 第三步:展开键值对数组,让每个键值对成为单独的文档 { $unwind: "$data" }, // 第四步:筛选出值数组包含目标值的项 { $match: { "data.v": { $in: ["chocolate"] } } }, // 第五步:只保留字段名字段 { $project: { key: "$data.k", _id: 0 } } ]); }) .then(result => { if (result.length > 0) { console.log("Key is>>>", result[0].key); // 输出: Key is>>> yumm } else { console.log("No matching key found"); } }) .catch(err => console.error(err));
聚合步骤解释:
$match:先定位到包含目标值的文档,减少后续处理的数据量;$objectToArray:把整个文档转换成[{k: 字段名, v: 字段值}]的数组格式,方便后续筛选;$unwind:把数组展开成单个文档,这样我们可以逐个检查每个字段;- 第二个
$match:筛选出值数组包含目标值的键值对; $project:只提取我们需要的字段名字段。
方案二:查询后在Node.js代码中遍历字段(适合字段固定且数量少的场景)
如果你的文档结构固定(只有yuck和yumm这两个数组字段),直接查询到文档后在代码里遍历检查会更简单高效:
const mongoose = require("mongoose"); const listSchema = new mongoose.Schema({ yuck: [String], yumm: [String] }); const List = mongoose.model("List", listSchema); List.create({ yuck: ["orange", "banana"], yumm: ["broccoli", "chocolate"] }) .then(() => { // 查询包含目标值的文档 return List.findOne({ $or: [{ yuck: "chocolate" }, { yumm: "chocolate" }] }); }) .then(doc => { if (!doc) { console.log("No document found with the specified value"); return; } // 遍历预设的字段列表,检查哪个数组包含目标值 const targetValue = "chocolate"; const fieldsToCheck = ["yuck", "yumm"]; for (const field of fieldsToCheck) { if (doc[field].includes(targetValue)) { console.log("Key is>>>", field); // 输出: Key is>>> yumm break; } } }) .catch(err => console.error(err));
这种方法的优势是代码更简洁,不需要写复杂的聚合管道,但缺点是如果后续新增了其他数组字段,需要手动更新fieldsToCheck列表。
内容的提问来源于stack exchange,提问作者URRGGHH-isacommonphrase
相关产品推荐
相关产品推荐

