Question

I have a mongo document:

"apps" : {
    "a" : {
        "last_login" : ISODate("2013-08-07T10:18:39.371Z")
    },
    "b" : {
        "last_login" : ISODate("2013-08-21T09:53:10.769Z")
    },
    "c" : {
        "last_login" : ISODate("2013-08-30T09:53:10.769Z")
    },
}

I want to get the highest last_login value? How do I do it?

Was it helpful?

Solution

Use the aggregation framework:

db.collection.aggregate([
    { "$project": {
        "answer": { "$cond": [
            { "$gt": [ "$a.last_login", "$b.last_login" ] },
            { "$cond": [
                { "$gt": [ "$a.last_login", "$c.last_login" ] },
                { 
                    "key": { "$literal": "a" }, 
                    "last_login": "$a.last_login"
                },
                {
                    "key": { "$literal": "c" },
                    "last_login": "$c.last_login"
                }
            ]},
            { "$cond": [
                { "$gt": [ "$b.last_login", "$c.last_login" ] },
                {
                    "key": { "$literal": "b" },
                    "last_login": "$b.last_login"
                },
                {
                    "key": { "$literal": "c" },
                    "last_login": "$c.last_login"
                },
            ]}
        ]}
    }}
])

It works, but it's actually quite mental. So the lesson to learn here it "do not use sub-documents in this way", and use arrays instead:

{
    "apps": [
      { "type": "a", "last_login": ISODate("2013-08-07T10:18:39.371Z") },
      { "type": "b", "last_login": ISODate("2013-08-21T09:53:10.769Z") },
      { "type": "c", "last_login": ISODate("2013-08-30T09:53:10.769Z") }
    ]
}

That makes things much more simple:

db.collection.aggregate(
    { "$unwind": "$apps" },
    { "$sort": { "apps.last_login": -1 } },
    { "$group": {
        "_id": "$_id",
        "answer": { "$first": "$apps" }
    }}
])

Much easier isn't it.

NOTE: The $literal operator was introduced in MongoDB 2.6. You might possibly find some references on the net to $const as an alternate operator, but this is not actually officially supported as that operator actually exists for another purpose.

You can do exactly the same thing in earlier server versions of MongoDB using the $cond operator instead:

"key": { "$cond": [ 1, "a", 0 ] }

This works as the result arguments to $cond are actually delivered as "literal" values, or "whatever you type in there", so no variable substitutions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top