Faiyaaz Khan
Faiyaaz Khan

Reputation: 61

How do I match an array of sub-documents in MongoDB?

Match documents if a value in an array of sub-documents is greater than some value only if the same document contains a field that is equal to some value

I have a collection that contains documents with an array of sub-documents. This array of sub-documents contains a field that dictates whether or not I can filter the documents in the collection based on another field in the sub-document. This'll make more sense when you see an example of the document.

    {  
    "_id":"ObjectId('XXX')",
    "Data":{  
        "A":"",
        "B":"-25.78562 ; 28.35629",
        "C":"165"
    },
    "SubDocuments":[  
        {  
            "_id":"ObjectId('XXX')",
            "Data":{  
                "Value":"XXX",
                "DataFieldId":"B"
            }
        },
        {  
            "_id":"ObjectId('XXX')",
            "Data":{  
                "Value":"",
                "DataFieldId":"A"
            }
        },
        {  
            "_id":"ObjectId('XXX')",
            "Data":{  
                "Value":"105",
                "DataFieldId":"Z"
            }
        }
    ]
}

I only want to match documents that contain sub-documents with a DataFieldId that is equal to Z but also filter for Values that are greater than 105 only if Data Field Id is equal to Z.

Upvotes: 2

Views: 633

Answers (2)

krishna Prasad
krishna Prasad

Reputation: 3812

This can be done by using the $elemMatch operator on sub-documents, for details you can click on provided link. For your problem you can try below query by using $elemMatch which is match simpler than aggregation:

    db.collectionName.find({
    "SubDocuments": { 
        $elemMatch: {
            "Data.DataFieldId": "Z" , 
            "Data.Value" : {$gte: 105}  
        } 
    } })

Its working fine, I have verified it locally, one modification you required is that you have to put the value of SubDocuments.Data.Value as Number or Long as per your requirements.

Upvotes: 0

Jitendra
Jitendra

Reputation: 3185

Try as below:

db.collection.aggregate([
{
    $project: {
        _id:1,
        Data:1,
        filteredSubDocuments: {
            $filter: {
                input: "$SubDocuments",
                as: "subDoc",
                cond: { 
                    $and: [
                        { $eq: ["$$subDoc.Data.DataFieldId", "Z"] },
                        { $gte: ["$$subDoc.Data.Value", 105] }
                    ]
                }
            }
        }
    }
}
])

Resulted response will be:

{
    "_id" : ObjectId("5cb09659952e3a179190d998"),
    "Data" : {
        "A" : "",
        "B" : "-25.78562 ; 28.35629",
        "C" : "165"
    },
    "filteredSubDocuments" : [
        {
            "_id" : "ObjectId('XXX')",
            "Data" : {
                "Value" : 105,
                "DataFieldId" : "Z"
            }
        }
    ]
}

Upvotes: 1

Related Questions