1

I have a collection in mongodb like this:

 db.country_list.find().pretty()
{
"_id" : ObjectId("53917321ccbc96175d7a808b"),
"countries" : [
    {
        "countryName" : "Afghanistan",
        "iso3" : "AFG",
        "callingCode" : "93"
    },
    {
        "countryName" : "Aland Islands",
        "iso3" : "ALA",
        "callingCode" : "358"
    },
    {
        "countryName" : "Albania",
        "iso3" : "ALB",
        "callingCode" : "355"
    }
              ]
}

like that i have 100 country details

i want to retrieve a country name where the calling code is 355. I have tried like this

db.country_list.find({countries: {$elemMatch :{ 'callingCode':'355'} } } )

and like this

 db.country_list.find({'countries.callingCode':'355'}).pretty()

but i am getting all records.How to get a specific record .Thanks in advance

1 Answer 1

1

What you want is the positional $ operator:

db.country_list.find(
   { "countries": { "$elemMatch" :{ "callingCode":"355"} } }
   { "countries.$": 1 }
)

Or even with the other syntax you tried:

db.country_list.find(
   { "countries.callingCode": "355"}
   { "countries.$": 1 }
)

This is because a "query" matches documents and is not a filter for the array contained in those documents. So the second argument there projects the field with the "position" that was matched on the query side.

If you need to match more than one array element, then you use the aggregation framework which has more flexibility:

db.country_list.aggregate([

    // Matches the documents that "contain" the match
    { "$match": {
        "countries.callingCode": "355"
    }},

    // Unwind the array to de-normalize as documents
    { "$unwind": "$countries" },

    // Match to "filter" the array content
    { "$match": {
        "countries.callingCode": "355"
    }},

    // Group back if you want an array
    { "$group": {
        "_id": "$_id",
        "countries": { "$push": "$countries" }
    }}
])

Or with MongoDB 2.6 or greater you can do this without the $unwind and $group:

db.country_list.aggregate([

    // Matches the documents that "contain" the match
    { "$match": {
        "countries.callingCode": "355"
    }},

    // Project with "$map" to filter
    { "$project": {
        "countries": {
            "$setDifference": [
                { "$map": {
                    "input": "$countries",
                    "as": "el",
                    "in": { 
                        "$cond": [
                            { "$eq": [ "$$el.callingCode", "355" ] }
                            "$$el",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }}

])
Sign up to request clarification or add additional context in comments.

3 Comments

It is really very useful answer for mogodb learners.Thanks once again
What if the condition matches multiple sub documents, If the first one only comes in that situation how to get all that mathced...?
@Mulagala This does match multiple sub-documents, which is the point and where this differs from the positional $ operator and $elemMatch in projection where you can match only one. This is kind of an old question (even if your own). So if you really need further clarification then as a new one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.