Reputation: 1648
I want to find only select array elements from a mongo document.like in following document I want to return only hard questions from array. am using mongo driver for java.
BasicDBObject query=new BasicDBObject("questionList.type", "hard");
DBCursor curssc = collection.find(query);
Document
{
"testpaperid": 1,
"testpaperNo": "science",
"questionList":
[
{
"question": "this is question no 1",
"type": "hard"
},
{
"question": "this is question no 2",
"type":"simple"
},
{
"question": "this is question no 3",
"type": "hard"
}
]
}
Upvotes: 1
Views: 1260
Reputation: 7840
If using $elemMatch operator it limits the contents of an <array>
field from the query results to contain only the first element matching the $elemMatch
condition.
So If you run this query :
db.collectionName.find({"questionList":{"$elemMatch":{"type":"hard"}}},{"questionList.type.$":1})
and above query equivalent code in java as below :
BasicDBObject eleMatch = new BasicDBObject();
eleMatch.put("type", "hard");
BasicDBObject elemMatchQuery = new BasicDBObject();
elemMatchQuery.put("$elemMatch", eleMatch);
BasicDBObject query = new BasicDBObject();
query.put("questionList", elemMatchQuery);
BasicDBObject projection = new BasicDBObject();
projection.put("questionList.type.$", 1);
DBCollection dbcoll = mongoTemplate.getCollection("collectionName");
DBObject object = dbcoll.find(query, projection);
This return only first matching type:hard
output contains "questionList" : [ { "question" : "this is question no 1", "type" : "hard" } ]
not all questionList
array which contains type:hard
For avoiding this should use mongo java aggregation driver and mongo aggregation query looks like :
db.collectionName.aggregate({
"$unwind": "$questionList"
}, {
"$match": {
"questionList.type": "hard"
}
}, {
"$group": {
"_id": "$_id",
"testpaperid": {
"$first": "$testpaperid"
},
"testpaperNo": {
"$first": "$testpaperNo"
},
"questionList": {
"$push": "$questionList"
}
}
}).pretty()
and this aggregation query in java as below :
// unwind questionList
DBObject unwind = new BasicDBObject("$unwind", "$questionList");
// create pipeline operations, with the $match
DBObject match = new BasicDBObject("$match", new BasicDBObject("questionList.type", "hard"));
// Now the $group operation
DBObject groupFields = new BasicDBObject("_id", "$group field");
groupFields.put("testpaperid", new BasicDBObject("$first", "$testpaperid"));
groupFields.put("testpaperNo", new BasicDBObject("$first", "$testpaperNo"));
groupFields.put("questionList", new BasicDBObject("$push", "$questionList"));
DBObject group = new BasicDBObject("$group", groupFields);
// run aggregation
List < DBObject > pipeline = Arrays.asList(unwind, match, group);
AggregationOutput output = collectionName.aggregate(pipeline);
for(DBObject result: output.results()) {
System.out.println(result);
}
Upvotes: 3
Reputation: 7418
When you use array operators in a regular query in MongoDB, it returns the documents that match the query criteria, and return the whole document, including the contents of the array field. This means that you cannot filter out some documents from an array field using a regular query.
But you can do that using the aggregation query. The following query is an aggregation query for mongo-shell, which you can easily translate to Java driver code:
db.quest.aggregate(
[
{$unwind: '$questionList'},
{$match: {'questionList.type': 'hard'}},
{$group:
{
_id: {
_id: '$_id',
testpaperid: '$testpaperid',
testpaperNo: '$testpaperNo'
},
questionList: {$push: '$questionList'}
}
},
{$project: {
_id: '$_id._id',
testpaperid: '$_id.testpaperid',
testpaperNo: '$_id.testpaperNo',
questionList: 1
}
}
]
)
Upvotes: 0