This particular structure may not be optimal, but if you have limited control over it, a solution involving mapReduce for JavaScript processing could be implemented:
db.collection.mapReduce(
function () {
var doc = this,
marks = doc.marks;
Object.keys( marks ).forEach(function(key) {
//emit( key, doc["marks"][key] );
var matched = Object.keys( marks[key] ).filter(function(inner) {
return inner.match(/^mark/);
});
if ( matched.length > 0 ) {
//emit( matched[0], 1 );
var myMatched = matched[0];
emit(
marks[key][myMatched], {
total: marks[key].total,
sem: key
}
);
}
});
},
function() {}, // null reducer not required
{ "out": { "inline": 1 } }
);
While not directly achieving the desired output, the above approach illustrates how mapReduce can handle such structures that are not easily queryable or analyzable through traditional methods.
A more efficient solution would involve reformatting the data like so:
{
"marks": [
{ "semester": "sem1", "mark": 10, "total": 100 },
{ "semester": "sem2", "mark": 20, "total": 200 },
{ "semester": "sem3", "mark": 30, "total": 300 }
]
}
To query this revised structure, utilize the aggregation framework which utilizes native code to traverse the data without relying on JavaScript notation:
db.collection.aggregate([
{ "$unwind": "$marks" },
{ "$project": {
"mark": "$marks.mark",
"total": "$marks.total",
"sem": "$marks.semester"
}}
])
Further customizations can be made based on specific analysis requirements and objectives within the given dataset.