Reputation: 1648
I have a survey document in mongodb, each survey have surveyRefId
for unique identification. I am not able to understand how to find sub-documents having questionType = hard in documents whose surveyRefid = 377 or 360.
Here is a sample document:
{
"json": {
"surveyRefId": 377,
"surveyName": "survey on sociology",
"questionsVoList": [
{
"questionId": "556708425215763c64b8af3d",
"questionText": "question no 1",
"questionTitle": "",
"questionType": "hard",
"preQuestion": true,
"questionOptions": [
{
"questionRefId": 0,
"optionType": "RADIOBUTTON",
"isanswer": true,
"optionText": "ch1"
}
]
},
{
"questionId": "556708425215763c64b8af3d",
"questionText": "question no 2",
"questionTitle": "",
"questionType": "simple",
"question": true,
"questionOptions": [
{
"questionRefId": 0,
"optionType": "RADIOBUTTON",
"isanswer": true,
"optionText": "ch1"
}
],
},
{
"questionId": "556708425215763c64b8af3d",
"questionText": "question no 3",
"questionTitle": "",
"questionType": "hard",
"questionOptions": [
{
"questionRefId": 0,
"optionType": "RADIOBUTTON",
"isanswer": true,
"optionText": "ch1"
},
{
"questionRefId": 0,
"optionType": "RADIOBUTTON",
"isanswer": false,
"optionText": "ch2"
}
],
}
]
}
}
EDIT-- Solution by using Java driver as per Sylvain Leroux
BasicDBObject matchSurvey = new BasicDBObject();
matchSurvey.put("$match", new BasicDBObject("json.surveyRefId", new BasicDBObject("$in", new Integer[]{377,360})));
BasicDBObject unwind = new BasicDBObject();
unwind.put("$unwind", "$json.questionsVoList");
BasicDBObject matchQuestion = new BasicDBObject();
matchQuestion.put("$match", new BasicDBObject("json.questionsVoList.questionType", "hard"));
HashMap map = new HashMap();
map.put("_id", "$_id");
map.put("questionsVoList", new BasicDBObject("$push", "$json.questionsVoList"));
BasicDBObject group = new BasicDBObject();
group.put("$group",map);
List<BasicDBObject> list = new ArrayList<BasicDBObject>();
list.add(matchSurvey);
list.add(unwind);
list.add(matchQuestion);
list.add(group);
AggregateIterable output = collection.aggregate(list, DBObject.class);
Upvotes: 1
Views: 1495
Reputation: 51980
"find sub-documents having questionType = "hard"
" can be understood in three different ways:
If you only want all documents having an "hard query, you will use find
and $elemMatch
:
db.test.find({"json.surveyRefId": { $in: [377, 360]},
"json.questionsVoList": {$elemMatch: {"questionType":"hard"}}})
If you need to find the first "hard" query of a document, you will combine the above query with the $
projection operator:
db.test.find({"json.surveyRefId": { $in: [377, 360]},
"json.questionsVoList": {$elemMatch: {"questionType":"hard"}}}
{"json.surveyRefId":1, "json.questionsVoList.$":1})
If you need to find all "hard" queries of the document, you will have to use the aggregation framework:
db.test.aggregate({$match: { "json.surveyRefId": { $in: [377, 360]} }},
{$unwind: "$json.questionsVoList"},
{$match: { "json.questionsVoList.questionType": "hard"}},
{$group: {_id: "$_id", questionsVoList: {$push: "$json.questionsVoList"}}}
)
$match
step will filter out unwanted documents based on their surveyRefId
$unwind
will produce a document for each sub-document$match
filters out unwanted documents based on questionType
$group
will combine all sub-documents back as one for a given _id
Producing:
{
"_id" : ObjectId("556828d002509ae174742d11"),
"questionsVoList" : [
{
"questionId" : "556708425215763c64b8af3d",
"questionText" : "question no 1",
"questionTitle" : "",
"questionType" : "hard",
"preQuestion" : true,
"questionOptions" : [
{
"questionRefId" : 0,
"optionType" : "RADIOBUTTON",
"isanswer" : true,
"optionText" : "ch1"
}
]
},
{
"questionId" : "556708425215763c64b8af3d",
"questionText" : "question no 3",
"questionTitle" : "",
"questionType" : "hard",
"questionOptions" : [
{
"questionRefId" : 0,
"optionType" : "RADIOBUTTON",
"isanswer" : true,
"optionText" : "ch1"
},
{
"questionRefId" : 0,
"optionType" : "RADIOBUTTON",
"isanswer" : false,
"optionText" : "ch2"
}
]
}
]
}
Upvotes: 5