1

I have a MongoDB collection indicators/

It returns statistical data such as:

/indicators/population

{
   id: "population"
   data : [
       {
       country : "A",
       value : 100
       },
       {
       country : "B",
       value : 150
       }
   ]
}

I would like to be able to limit the response to specific countries. MongoDB doesn't seem to support this, so should I:

  1. Restructure the MongoDB collection setup to allow this via native find()
  2. Extend my API so that it allows filtering of the data array before returning to client
  3. Other?

2 Answers 2

1

This is actually a very simple operation that just involves "projection" using the positional $ operator in order to match a given condition. In the case of a "singular" match that is:

db.collection.find(
    { "data.country": "A" },
    { "data.$": 1 }
)

And that will match the first element in the array which matches the condition as given in the query.

For more than one match, you need to invoke the aggregation framework for MongoDB:

db.collection.agggregate([

    // Match documents that are possible first
    { "$match": {
        "data.country": "A"
    }},

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

    // Actually filter the now "expanded" array items
    { "$match": {
        "data.country": "A"
    }},

    // Group back together
    { "$group": {
        "_id": "$_id",
        "data": { "$push": "$data" }
    }}
])

Or with MongoDB 2.6 or greater, a little bit cleaner, or at least without the $unwind:

db.collection.aggregate({

    // Match documents that are possible first
    { "$match": {
        "data.country": "A"
    }},

    // Filter out the array in place
    { "$project": {
        "data": {
            "$setDifference": [
                {
                    "$map": {
                        "input": "$data",
                        "as": "el", 
                        "in": {
                            "$cond": [
                                { "$eq": [ "$$el.country", "A" },
                                "$$el",
                                false
                            ]
                        }
                    }
                },
                [false]
            ]
        }
    }}
])
Sign up to request clarification or add additional context in comments.

Comments

0

If my understanding of the problem is ok, then you can use :

db.population.find({"population.data.country": {$in : ["A", "C"]}});

1 Comment

Not sure you did understand the problem as it seems to be asking about returning only "specific" results from an array. This would just return documents that "contained" those contents. There are keywords in the question such as "filtering" that suggests what is required.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.