Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort by subdocuments fields in mongo

Tags:

Given the following collection:

[
    {
        name: User1
        metadata: [
            {k:"score", v: 5},
            {k:"other", v: 10}
        ]
    },
    {
        name: User2
        metadata: [
            {k:"score", v: 1},
            {k:"other", v: 1}
        ]
    },
    {
        name: User3
        metadata: [
            {k:"score", v: 2},
            {k:"other", v: 0}
        ]
    }
]

How can you sort these items by their "score"? I can sort by the metadata.v field, but I am not sure how to only consider the "v" values for subdocuments that match "k":"score"

The expected output would be:

[
    {
        name: User2
        metadata: [
            {k:"score", v: 1},
            {k:"other", v: 1}
        ]
    },
    {
        name: User3
        metadata: [
            {k:"score", v: 2},
            {k:"other", v: 0}
        ]
    },
    {
        name: User1
        metadata: [
            {k:"score", v: 5},
            {k:"other", v: 10}
        ]
    }
]
like image 381
Antonio O. Avatar asked Jul 25 '16 15:07

Antonio O.


1 Answers

An alternative solution could look like this, whereby the final projection stage is optional if you can live with an additional scoredata property.

db.yourCollection.aggregate([
    {
        $project: {
            name: 1,
            metadata: 1,
            scoredata: {
                $filter: {
                    input: '$metadata',
                    as: 'metadoc',
                    cond: {
                        $eq: [ '$$metadoc.k', 'score' ]
                    }
                }
            }
        }
    },
    {
        $sort: {
            scoredata: 1
        }
    },
    {
        $project: {
            name: 1,
            metadata: 1            
        }
    }
])  

Output looks like this

/* 1 */
{
    "_id" : ObjectId("5796387b3360e0a2e9dd9fc3"),
    "name" : "User2",
    "metadata" : [ 
        {
            "k" : "score",
            "v" : 1
        }, 
        {
            "k" : "other",
            "v" : 1
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("5796387b3360e0a2e9dd9fc4"),
    "name" : "User3",
    "metadata" : [ 
        {
            "k" : "score",
            "v" : 2
        }, 
        {
            "k" : "other",
            "v" : 0
        }
    ]
}

/* 3 */
{
    "_id" : ObjectId("5796387b3360e0a2e9dd9fc2"),
    "name" : "User1",
    "metadata" : [ 
        {
            "k" : "score",
            "v" : 5
        }, 
        {
            "k" : "other",
            "v" : 10
        }
    ]
}
like image 182
DAXaholic Avatar answered Sep 28 '22 01:09

DAXaholic