MongoDB $rand

In MongoDB, the $rand aggregation pipeline operator returns a random float between 0 and 1.

The floating point value has up to 17 digits after the decimal point. Any trailing zeros are dropped, so the number of digits may vary.

The $rand operator was introduced in MongoDB 4.4.2.

Example

Suppose we have a collection called cats with the following documents:

{ "_id" : 1, "name" : "Scratch" }
{ "_id" : 2, "name" : "Meow" }
{ "_id" : 3, "name" : "Fluffy" }

We can use the $rand operator to generate a random number for each cat:

db.cats.aggregate(
   [
     {
       $project:
          {
            randomNumber: { $rand: {} }
          }
     }
   ]
)

Result:

{ "_id" : 1, "randomNumber" : 0.5593964875463812 }
{ "_id" : 2, "randomNumber" : 0.04357301703691149 }
{ "_id" : 3, "randomNumber" : 0.7556877215199272 }

The $rand operator doesn’t accept any arguments – you simply call it by using $rand: {}.

Also, $rand generates a new number each time it is called. Therefore, running the above code multiple times will produce a different random number for each cat.

Just to demonstrate this, I’ll run it again and here’s the new result:

{ "_id" : 1, "randomNumber" : 0.19672627212049873 }
{ "_id" : 2, "randomNumber" : 0.05513133909795318 }
{ "_id" : 3, "randomNumber" : 0.7509841462815067 }

We can see that the random numbers are different to the ones generated in the previous example.

Random Numbers Greater than 1

As mentioned, $rand returns a random float between 0 and 1. This is fine if we don’t mind getting a zero, followed by up to 17 random decimal places.

But what if we want a random number greater than 1?

In such cases, we can use the $multiply operator to multiply the result of $rand.

Example:

db.cats.aggregate(
   [
     {
       $project:
          {
            randomNumber: { $multiply: [ { $rand: {} }, 10 ] }
          }
     }
   ]
)

Result:

{ "_id" : 1, "randomNumber" : 1.958938543288535 }
{ "_id" : 2, "randomNumber" : 4.437057321655847 }
{ "_id" : 3, "randomNumber" : 8.238909118372334 }

Random Integer

We might also want to do away with the fractional part. In this case, we can use an operator such as $floor to remove the decimal portion, therefore leaving an integer.

Example:

db.cats.aggregate(
   [
     {
       $project:
          {
            name: 1,
            randomNumber: { 
              $floor: { 
                $multiply: [ { $rand: {} }, 10 ] 
                } 
              }
          }
     }
   ]
)

Result:

{ "_id" : 1, "name" : "Scratch", "randomNumber" : 0 }
{ "_id" : 2, "name" : "Meow", "randomNumber" : 5 }
{ "_id" : 3, "name" : "Fluffy", "randomNumber" : 7 }

Here it is again, but this time we multiply it by 100:

db.cats.aggregate(
   [
     {
       $project:
          {
            name: 1,
            randomNumber: { 
              $floor: { 
                $multiply: [ { $rand: {} }, 100 ] 
                } 
              }
          }
     }
   ]
)

Result:

{ "_id" : 1, "name" : "Scratch", "randomNumber" : 18 }
{ "_id" : 2, "name" : "Meow", "randomNumber" : 62 }
{ "_id" : 3, "name" : "Fluffy", "randomNumber" : 92 }

Save the Results

As mentioned, $rand generates a new random float each time it’s called. This is fine if we want a new random number each time we run the code, but what if we want to store the random number in each document?

To store the random number in the document, we can use the $addFields operator (or its alias $set) to add the new field to the document.

Example:

db.cats.aggregate(
   [
      { $set: { randomNumber: { $multiply: [ { $rand: {} }, 100 ] } } },
      { $set: { randomNumber: { $floor: "$randomNumber" } } },
      { $merge: "cats" }
   ]
)

In this example, we separate the operation across two $set stages and a $merge stage.

The $merge stage writes the results of the aggregation pipeline to a specified collection, and it must be the last stage in the pipeline.

Now when we return the documents from that collection (e.g. by using a method like find()), we can see that each document contains the new field with the random number:

db.cats.find()

Result:

{ "_id" : 1, "name" : "Scratch", "randomNumber" : 61 }
{ "_id" : 2, "name" : "Meow", "randomNumber" : 86 }
{ "_id" : 3, "name" : "Fluffy", "randomNumber" : 73 }

Now the random number is persistent. We can return the documents as many times as we like, and the random number will remain the same.

Let’s run find() again:

db.cats.find()

Result:

{ "_id" : 1, "name" : "Scratch", "randomNumber" : 61 }
{ "_id" : 2, "name" : "Meow", "randomNumber" : 86 }
{ "_id" : 3, "name" : "Fluffy", "randomNumber" : 73 }

Exactly the same random number.