Pitty
Pitty

Reputation: 329

Filter K-V in array with Mongodb

I have a mongodb data base like this:

{
    "_id" : ObjectId("530d24150fef5d9b065909ca"),
    "name" : "name 1",
    "my_array" : [
        {"key" : "date", "value": 19},
        {"key" : "id", "value": 5}
     ]
}
{
    "_id" : ObjectId("530d24150fef5d9b065909ca"),
    "name" : "name 2",
    "my_array" : [
        {"key" : "date", "value": 9},
        {"key" : "id", "value": 11}
     ]
}
{
    "_id" : ObjectId("530d24150fef5d9b065909ca"),
    "name" : "name 3",
    "my_array" : [
        {"key" : "date", "value": 10},
        {"key" : "id", "value": 13},
        {"key" : "name", "value": 'test'},
     ]
}

I want to make a query which depends on the K-V in my_array. I know to list the items have the key-name:

db.test.find({"my_array.key": 'name'})

But, I don't know how to filter the items with the key-value, Like get the item which key is 'id' and value bigger than 10. I this sample the result must be:

{
    "_id" : ObjectId("530d24150fef5d9b065909ca"),
    "name" : "name 2",
    "my_array" : [
        {"key" : "date", "value": 9},
        {"key" : "id", "value": 11}
     ]
}
{
    "_id" : ObjectId("530d24150fef5d9b065909ca"),
    "name" : "name 3",
    "my_array" : [
        {"key" : "date", "value": 10},
        {"key" : "id", "value": 13},
        {"key" : "name", "value": 'test'},
     ]
}

And, I had tried about the follow command line:

db.test.find({"my_array.key": 'id', "my_array.value": {$gt : 10}})
db.test.find({"my_array":{"key": 'id', "value": {$gt : 10}}})

Those are all not work...

Thanks in advance.

Upvotes: 1

Views: 548

Answers (3)

Neil Lunn
Neil Lunn

Reputation: 151072

You need to use $elemMatch to find a document that contains both of the elements that match your conditions:

db.test.find(
    {
        "my_array": { "$elemMatch":{ 
            "key": "id", "value": { "$gt" : 10 }
        }}
    },
    {
        "my_array.$": 1
    }
)

Keep in mind that this is matching the document and not the array elements. The use of projection here will only get the first value.

If you have multiple entries to filter within the array you need to use aggregate:

db.test.aggregate([
    { "$match": {
        "my_array": { "$elemMatch":{ 
            "key": "id", "value": { "$gt" : 10 }
        }}
    }},
    { "$unwind": "$my_array" },
    { "$match": {
        "my_array.key": "id",
        "my_array.value": { "$gt" : 10 }
    }},
    { "$group": {
        "_id": "$_id",
        "name": { "$first": "$name" },
        "my_array": { "$push": "$my_array" }
    }}
])

Upvotes: 2

Mayuri
Mayuri

Reputation: 412

Refer this to find ans of your question.
db.test.find({my_array: {$elemMatch: {key: 'id', value: {$gt: 10}}}})

Upvotes: 1

dikesh
dikesh

Reputation: 3125

You can use $elemMatch to achieve the same.

Try following query.

db.test.find({my_array: {$elemMatch: {key: 'id', value: {$gt: 10}}}})

Upvotes: 1

Related Questions