find only matching subdocument from array

8,975 views
Skip to first unread message

Monika Shah

unread,
Oct 2, 2017, 8:14:15 AM10/2/17
to mongodb-user
What is equivalent query in Mongo for
Select only those grades subdocument from restaurant sample collection which match some criteria i.e. score>10
Note: One restaurant may have many grade subdocument with satisfied criteria

Monika Shah

unread,
Oct 2, 2017, 8:37:34 AM10/2/17
to mongodb-user
>  db.restaurants.find({"grades.score":{$gt:10}},{_id:0,grades:{$elemMatch:{score:{$gt:10}}}}).pretty()

Monika Shah

unread,
Oct 2, 2017, 9:28:36 AM10/2/17
to mongodb-user
This query displays only one matching element from subdocument array. How to display only all matching elements from array ?
>  db.restaurants.find({"grades.
score":{$gt:10}},{_id:0,grades:{$elemMatch:{score:{$gt:10}}}}).pretty()


Kevin Adistambha

unread,
Oct 3, 2017, 9:29:08 PM10/3/17
to mongodb-user

Hi,

The $elemMatch projection has the limitation that it will only project the first matching element. This is mentioned in the $elemMatch projection documentation page.

To display all matching elements, you need to use the Aggregation framework.

You didn’t give an example document you’re trying to match, but I assume it’s similar to this:

{
  "name": "Restaurant A",
  "grades": [
    {
      "reviewer": "a",
      "score": 10
    },
    {
      "reviewer": "b",
      "score": 10
    },
    {
      "reviewer": "c",
      "score": 9
    }
  ]
}

The aggregation stages you can use depends on your MongoDB version. If you’re using MongoDB 3.4, you can use the new $addFields stage:

db.restaurants.aggregate([
    // match the relevant document
    {$match:{'grades.score':{$gte: 10}}},
    // filter out irrelevant array entries
    {$addFields: {
        top_reviews: {
            $filter: {
                input: '$grades',
                cond: {
                    $gte: ['$$this.score', 10]
                }
            }
        }
    }},
    // project only the relevant fields
    {$project: {_id: 0, grades: 0}}
])

or if you’re using older versions of MongoDB, you would need to use the relatively less-performant $unwind stage:

db.restaurants.aggregate([
    // match relevant documents
    {$match: {'grades.score': {$gte: 10}}},
    // unwind the grades array
    {$unwind: '$grades'},
    // match the relevant unwound array element
    {$match: {'grades.score': {$gte: 10}}},
    // re-group the array elements
    {$group: {
        _id: '$name',
        top_reviews: {$push: '$grades'}
    }}
])

Either way, both methods should result in:

{ "name": "Restaurant A", "top_reviews": [   {   "reviewer": "a",   "score": 10 },   {   "reviewer": "b",   "score": 10 } ] }

Here are the relevant documentations regarding the aggregation stages:

Best regards,
Kevin

Monika Shah

unread,
Oct 12, 2017, 12:24:30 PM10/12/17
to mongodb-user
Thank you for proper answer.
But, why to specify filter condition i.e. score >10  mutiple times?


On Monday, October 2, 2017 at 5:44:15 PM UTC+5:30, Monika Shah wrote:

Kevin Adistambha

unread,
Oct 16, 2017, 10:20:36 PM10/16/17
to mongodb-user

Hi

But, why to specify filter condition i.e. score >10 mutiple times?

I believe you are referring to the $unwind example. This is due to how $unwind works, i.e. it’s unwinding the array into separate documents. Hence the first $match is to filter irrelevant documents, and the second $match is to filter out irrelevant unwound array entries.

Please see the $unwind documentation page.

Best regards,
Kevin

Tran Quan Dinh

unread,
Nov 18, 2018, 4:54:55 PM11/18/18
to mongodb-user
Can you help me to convert this query to java.
Thanks.

Kevin Adistambha

unread,
Nov 26, 2018, 10:48:04 PM11/26/18
to mongodb-user

Hi Tran

Can you help me to convert this query to java.

I’m not certain what query you want to convert to Java. In general, the Java driver syntax follows the mongo shell syntax quite closely. See MongoDB Driver Quick Start for some examples.

If you need more help, could you open a new thread with more details, e.g. your Java driver version and the query you’re having issues with.

Best regards,
Kevin

Reply all
Reply to author
Forward
0 new messages