3

My documents looks like this.

{
"_id" : ObjectId("572c4bffd073dd581edae045"),
"name" : "What's New in PHP 7",
"description" : "PHP 7 is the first new major version number of PHP since 2004. This course shows what's new, and what's changed.",
"difficulty_level" : "Beginner",
"type" : "Normal",
"tagged_skills" : [ 
    {
        "_id" : "5714e894e09a0f7d804b2254",
        "name" : "PHP"
    }
],
"created_at" : 1462520831.649,
"updated_at" : 1468233074.243    }

Is it possible to get recent 5 documents and total count in a single query. I am using two queries for this requirement as given below.

db.course.find().sort({created_at:-1}).limit(5)
db.course.count()

4 Answers 4

7

This is a perfect job for the aggregation framework.

db.course.aggregate(
    [
        { "$sort": { "created_at": -1 }},
        { "$group": {
            "_id": null, 
            "docs": { "$push": "$$ROOT" }, 
            "count": { "$sum": 1 }
        }},
        { "$project": { "_id": 0, "count": 1, "docs": { "$slice": [ "$docs", 5 ] } }}
    ]
)

If your MongoDB server doesn't support $slice then you need to use the ugly and inefficient approach.

db.course.aggregate(
    [
        { "$sort": { "created_at": -1 }},
        { "$group": {
            "_id": null, 
            "docs": { "$push": "$$ROOT" }, 
            "count": { "$sum": 1 }
        }},
        { "$unwind": "$docs" },
        { "$limit": 5 }
    ]
)
Sign up to request clarification or add additional context in comments.

3 Comments

can you explain me a little about $$ROOT.
@jarryjafery $$ROOT is a system variable in MongoDB that gives you access to the document being processed. I will add an explanation to my answer when I have a little time.
Why the second query is inefficient?
3

You can implement this easily with $facet

myCollection.aggregate([
    {
      $facet: {
        count: [{ $count: "value" }],
        data: [{ $sort: { _id: -1 } }, { $skip: skip }, { $limit: limit }]
      }
    },
    { $unwind: "$count" },
    { $set: { count: "$count.value" } }
])

the return result will be like:

[
  {
    "count": 234,
    "data": [
      // ...
    ]
  }
]

Comments

0

@styvane I tested in person, this query is even less efficient than twice queries.

// get count 
db.course.aggregate([{$match:{}}, {$count: "count"}]);
    // get docs
db.course.aggregate(
       [
            {$match:{}},
            { "$sort": { "created_at": -1 }},
            {"$skip": offset},
            {"$limit": limit}
        ]
)

Comments

-5

No, there is no other way. Two queries - one for count - one with limit.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.