Mongoose/Node:无字段名筛选数组元素的技术问询
Got it, let's work through this problem step by step. The tricky part here is that your data array holds sub-arrays with no explicit field names—we have to target elements by their position in the sub-array instead of a named key.
Why Your Initial $elemMatch Attempt Failed
$elemMatch works well for matching objects in arrays, but since we're dealing with arrays of arrays, we need to go a level deeper and reference the index of the element we want to check (in your case, the first element of each sub-array, like "ABC").
Recommended Approach: Use MongoDB Aggregation Framework
The aggregation pipeline gives us the flexibility to filter the nested data array while preserving the original document structure. Here's how to implement it in your route:
router.get("/", (req, res) => { // Pull the filter value from request query (or hardcode for testing) const filterValue = req.query.key || "ABC"; model.aggregate([ { $addFields: { // Iterate over each item in the datatable array "datatable": { $map: { input: "$datatable", as: "table", in: { // Filter the data array to keep only sub-arrays where first element matches our value data: { $filter: { input: "$$table.data", as: "row", cond: { $eq: [ { $arrayElemAt: ["$$row", 0] }, filterValue ] } } } } } } } } ]) .then(results => { res.send(results); }) .catch(err => { console.error("Error filtering documents:", err); res.status(500).send({ error: "Failed to filter data" }); }); });
Breakdown of the Code:
$addFields: Updates thedatatablefield without replacing the entire document, keeping other fields intact.$map: Loops through each object in thedatatablearray (sincedatatableitself is an array of objects).$filter: For eachdataarray inside thedatatableobjects, we retain only the sub-arrays where:$arrayElemAt: ["$$row", 0]grabs the first element of the sub-array (e.g., "ABC", "DDE").- We compare that value to our
filterValueusing$eqto check for a match.
Alternative (Limited) Find Method
If you prefer using find, note this approach has limitations—it only keeps the first matching datatable element and the first matching sub-array in data:
router.get("/", (req, res) => { const filterValue = req.query.key || "ABC"; model.find( // Match documents where any datatable.data sub-array contains our value as first element { "datatable.data": { $elemMatch: { $elemMatch: { $eq: filterValue } } } }, // Project only the matching parts (only returns first match in each array) { "datatable.$.data": { $elemMatch: { $elemMatch: { $eq: filterValue } } } } ) .then(results => res.send(results)) .catch(err => res.status(500).send(err)); });
Stick with the aggregation method if you need to retain all matching sub-arrays in data and all elements in datatable.
内容的提问来源于stack exchange,提问作者Reymart

