I have a node.js server using express and mongoose and I also have a Json structure of :
[
{
"_id": "63dbaf5daabee478202ae59f",
"experimentId": "85a91abe-ef2f-416f-aa13-ec1bdf5d9766",
"experimentData": [
{
"scanId": 1652890241,
"scanData": [
{
"areaName": "A1",
"areaData": [],
"_id": "63dbaf94aabee478202ae5a5"
},
...
],
"_id": "63dbaf6caabee478202ae5a3"
},
...
],
"__v": 2
},
...
]
How can I create a query to return a single object from the scanData array like
{
"areaName": "A1",
"areaData": [],
"_id": "63dbb006e322869df811eea4"
}
The best I was able to do was:
// * Get all shapes in a well/area
// ! uses the experiment id, scan id and areaName
router.get("/:id/scan/:scanId/area/:areaName", async (req, res) => {
try {
const experiment = await Experiment.findOne({
experimentId: req.params.id,
experimentData: {
$elemMatch: {
scanId: req.params.scanId,
scanData: {
$elemMatch: {
areaName: req.params.areaName
}
}
}
}
}, {'experimentData.scanData.$': 1})
console.log(experiment)
if (!experiment || experiment.length === 0) res.status(404).json({})
else {
res.send(experiment.experimentData[0])
}
} catch (err) {
res.status(500).json({ message: err.message })
}
})
But that just returned the scanData array it would be great if I could go one level deeper and just get the object with the areaName. I also tried some solutions with $aggregate but was not able to get any data displayed it kept returning an empty array
CodePudding user response:
You can $match
by your criteria layer-by-layer and $unwind
to get the final scanData
object in an aggregation pipeline. Use $replaceRoot
to get only the scanData
object.
db.collection.aggregate([
{
"$match": {
"experimentId": "85a91abe-ef2f-416f-aa13-ec1bdf5d9766"
}
},
{
"$unwind": "$experimentData"
},
{
"$match": {
"experimentData.scanId": 1652890241
}
},
{
"$unwind": "$experimentData.scanData"
},
{
"$match": {
"experimentData.scanData.areaName": "A1"
}
},
{
"$replaceRoot": {
"newRoot": "$experimentData.scanData"
}
}
])