$denseRank (aggregation)
On this page
Definition
New in version 5.0.
Returns the document position (known as the rank) relative to other
documents in the $setWindowFields
stage partition.
The $setWindowFields
stage sortBy field value determines the document rank. For
more information on how MongoDB compares fields with different types,
see BSON comparison order.
If multiple documents occupy the same rank, $denseRank
places
the document with the subsequent value at the next rank without any gaps
(see Behavior).
$denseRank
is only available in the
$setWindowFields
stage.
$denseRank
syntax:
{ $denseRank: { } }
$denseRank
does not accept any parameters.
Behavior
$rank
and$denseRank
differ in how they rank duplicate sortBy field values. For example, with sortBy field values of 7, 9, 9, and 10:$denseRank
ranks the values as 1, 2, 2, and 3. The duplicate 9 values have a rank of 2, and 10 has a rank of 3. There is no gap in the ranks.$rank
ranks the values as 1, 2, 2, and 4. The duplicate 9 values have a rank of 2, and 10 has a rank of 4. There is a gap in the ranks for 3.
Documents with a
null
value for a sortBy field or documents missing the sortBy field are assigned a rank based on the BSON comparison order. See the example in Rank Partitions Containing Duplicate Values, Nulls, or Missing Data.Starting in MongoDB 8.0,
null
and missing field values in$denseRank
and$rank
sortBy operations are treated the same when calculating rankings. This change makes the behavior ofdenseRank
andrank
consistent with$sort
.
See the example in Dense Rank for Duplicate, Null, and Missing Values.
Examples
Dense Rank Partitions by an Integer Field
Create a cakeSales
collection that contains cake sales in the states
of California (CA
) and Washington (WA
):
db.cakeSales.insertMany( [ { _id: 0, type: "chocolate", orderDate: new Date("2020-05-18T14:10:30Z"), state: "CA", price: 13, quantity: 120 }, { _id: 1, type: "chocolate", orderDate: new Date("2021-03-20T11:30:05Z"), state: "WA", price: 14, quantity: 140 }, { _id: 2, type: "vanilla", orderDate: new Date("2021-01-11T06:31:15Z"), state: "CA", price: 12, quantity: 145 }, { _id: 3, type: "vanilla", orderDate: new Date("2020-02-08T13:13:23Z"), state: "WA", price: 13, quantity: 104 }, { _id: 4, type: "strawberry", orderDate: new Date("2019-05-18T16:09:01Z"), state: "CA", price: 41, quantity: 162 }, { _id: 5, type: "strawberry", orderDate: new Date("2019-01-08T06:12:03Z"), state: "WA", price: 43, quantity: 134 } ] )
This example uses $denseRank
in the
$setWindowFields
stage to output the quantity
dense rank
of the cake sales for each state
:
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { quantity: -1 }, output: { denseRankQuantityForState: { $denseRank: {} } } } } ] )
In the example:
partitionBy: "$state"
partitions the documents in the collection bystate
. There are partitions forCA
andWA
.sortBy: { quantity: -1 }
sorts the documents in each partition byquantity
in descending order (-1
), so the highestquantity
is first.
output
sets thedenseRankOrderDateForState
field to theorderDate
dense rank using$denseRank
, as shown in the following results.
{ "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "denseRankQuantityForState" : 1 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "denseRankQuantityForState" : 2 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "denseRankQuantityForState" : 3 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "denseRankQuantityForState" : 1 } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "denseRankQuantityForState" : 2 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "denseRankQuantityForState" : 3 }
Dense Rank Partitions by a Date Field
This example shows how to use dates with $denseRank
in the
$setWindowFields
stage to output the orderDate
dense
rank of the cake sales for each state
:
db.cakeSales.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { orderDate: 1 }, output: { denseRankOrderDateForState: { $denseRank: {} } } } } ] )
In the example:
partitionBy: "$state"
partitions the documents in the collection bystate
. There are partitions forCA
andWA
.sortBy: { orderDate: 1 }
sorts the documents in each partition byorderDate
in ascending order (1
), so the earliestorderDate
is first.
output
sets thedenseRankOrderDateForState
field to theorderDate
rank using$denseRank
, as shown in the following results.
{ "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "denseRankOrderDateForState" : 1 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "denseRankOrderDateForState" : 2 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "denseRankOrderDateForState" : 3 } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "denseRankOrderDateForState" : 1 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "denseRankOrderDateForState" : 2 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "denseRankOrderDateForState" : 3 }
Dense Rank for Duplicate, Null, and Missing Values
Create a cakeSalesWithDuplicates
collection where:
Cake sales are placed in the state of California (
CA
) and Washington (WA
).Documents 6 to 8 have the same
quantity
andstate
as document 5.Document 9 has the same
quantity
andstate
as document 4.Document 10 has a
null
quantity
.Document 11 is missing the
quantity
.
db.cakeSalesWithDuplicates.insertMany( [ { _id: 0, type: "chocolate", orderDate: new Date("2020-05-18T14:10:30Z"), state: "CA", price: 13, quantity: 120 }, { _id: 1, type: "chocolate", orderDate: new Date("2021-03-20T11:30:05Z"), state: "WA", price: 14, quantity: 140 }, { _id: 2, type: "vanilla", orderDate: new Date("2021-01-11T06:31:15Z"), state: "CA", price: 12, quantity: 145 }, { _id: 3, type: "vanilla", orderDate: new Date("2020-02-08T13:13:23Z"), state: "WA", price: 13, quantity: 104 }, { _id: 4, type: "strawberry", orderDate: new Date("2019-05-18T16:09:01Z"), state: "CA", price: 41, quantity: 162 }, { _id: 5, type: "strawberry", orderDate: new Date("2019-01-08T06:12:03Z"), state: "WA", price: 43, quantity: 134 }, { _id: 6, type: "strawberry", orderDate: new Date("2020-01-08T06:12:03Z"), state: "WA", price: 41, quantity: 134 }, { _id: 7, type: "strawberry", orderDate: new Date("2020-01-01T06:12:03Z"), state: "WA", price: 34, quantity: 134 }, { _id: 8, type: "strawberry", orderDate: new Date("2020-01-02T06:12:03Z"), state: "WA", price: 40, quantity: 134 }, { _id: 9, type: "strawberry", orderDate: new Date("2020-05-11T16:09:01Z"), state: "CA", price: 39, quantity: 162 }, { _id: 10, type: "strawberry", orderDate: new Date("2020-05-11T16:09:01Z"), state: "CA", price: 39, quantity: null }, { _id: 11, type: "strawberry", orderDate: new Date("2020-05-11T16:09:01Z"), state: "CA", price: 39 } ] )
This example uses $denseRank
in the
$setWindowFields
stage to output the quantity
dense rank
from the cakeSalesWithDuplicates
collection for each state
:
db.cakeSalesWithDuplicates.aggregate( [ { $setWindowFields: { partitionBy: "$state", sortBy: { quantity: -1 }, output: { denseRankQuantityForState: { $denseRank: {} } } } } ] )
In the example:
partitionBy: "$state"
partitions the documents in the collection bystate
. There are partitions forCA
andWA
.sortBy: { quantity: -1 }
sorts the documents in each partition byquantity
in descending order (-1
), so the highestquantity
is first.
output
sets thedenseRankQuantityForState
field to thequantity
dense rank using$denseRank
.
In the following example output:
The documents with the same
quantity
andstate
have the same rank and there is no gap between the ranks. This differs from$rank
that has a gap between the ranks (for an example, see Rank Partitions Containing Duplicate Values, Nulls, or Missing Data).The document with the
null
quantity
and then the document with the missingquantity
are ranked the lowest in the output for theCA
partition. This sorting is the result of the BSON comparison order, which sortsnull
and missing values after number values in this example.
{ "_id" : 4, "type" : "strawberry", "orderDate" : ISODate("2019-05-18T16:09:01Z"), "state" : "CA", "price" : 41, "quantity" : 162, "denseRankQuantityForState" : 1 } { "_id" : 9, "type" : "strawberry", "orderDate" : ISODate("2020-05-11T16:09:01Z"), "state" : "CA", "price" : 39, "quantity" : 162, "denseRankQuantityForState" : 1 } { "_id" : 2, "type" : "vanilla", "orderDate" : ISODate("2021-01-11T06:31:15Z"), "state" : "CA", "price" : 12, "quantity" : 145, "denseRankQuantityForState" : 2 } { "_id" : 0, "type" : "chocolate", "orderDate" : ISODate("2020-05-18T14:10:30Z"), "state" : "CA", "price" : 13, "quantity" : 120, "denseRankQuantityForState" : 3 } { "_id" : 10, "type" : "strawberry", "orderDate" : ISODate("2020-05-11T16:09:01Z"), "state" : "CA", "price" : 39, "quantity" : null, "denseRankQuantityForState" : 4 } { "_id" : 11, "type" : "strawberry", "orderDate" : ISODate("2020-05-11T16:09:01Z"), "state" : "CA", "price" : 39, "denseRankQuantityForState" : 5 } { "_id" : 1, "type" : "chocolate", "orderDate" : ISODate("2021-03-20T11:30:05Z"), "state" : "WA", "price" : 14, "quantity" : 140, "denseRankQuantityForState" : 1 } { "_id" : 5, "type" : "strawberry", "orderDate" : ISODate("2019-01-08T06:12:03Z"), "state" : "WA", "price" : 43, "quantity" : 134, "denseRankQuantityForState" : 2 } { "_id" : 6, "type" : "strawberry", "orderDate" : ISODate("2020-01-08T06:12:03Z"), "state" : "WA", "price" : 41, "quantity" : 134, "denseRankQuantityForState" : 2 } { "_id" : 7, "type" : "strawberry", "orderDate" : ISODate("2020-01-01T06:12:03Z"), "state" : "WA", "price" : 34, "quantity" : 134, "denseRankQuantityForState" : 2 } { "_id" : 8, "type" : "strawberry", "orderDate" : ISODate("2020-01-02T06:12:03Z"), "state" : "WA", "price" : 40, "quantity" : 134, "denseRankQuantityForState" : 2 } { "_id" : 3, "type" : "vanilla", "orderDate" : ISODate("2020-02-08T13:13:23Z"), "state" : "WA", "price" : 13, "quantity" : 104, "denseRankQuantityForState" : 3 }