Skip to content

Commit f0d1b2c

Browse files
mungitoperritoandf-mongodb
authored andcommitted
DOCSP-13968 update $rand with new examples
1 parent 2f8a024 commit f0d1b2c

File tree

2 files changed

+176
-100
lines changed

2 files changed

+176
-100
lines changed

source/reference/operator/aggregation/rand.txt

Lines changed: 79 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -36,134 +36,131 @@ dropped so the actual number of digits may vary.
3636
Examples
3737
--------
3838

39-
This code initializes a ``randomSamples`` collection with 100 documents
40-
that is used in the following examples.
39+
Generate Random Data Points
40+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
4141

42-
.. code-block:: javascript
43-
44-
N = 100
45-
bulk = db.randomSamples.initializeUnorderedBulkOp()
46-
for ( i = 0; i < N; i++) { bulk.insert( {_id: i, random: 0 } ) }
47-
bulk.execute()
48-
49-
50-
Usage with Update Queries
51-
~~~~~~~~~~~~~~~~~~~~~~~~~
52-
53-
The ``$rand`` operator can be used with update query operations. In
54-
this example :method:`~db.collection.updateMany()` uses the ``$rand``
55-
operator to insert a different random number into each document
56-
in the ``randomSamples`` collection.
42+
This example models charitable donations. The collection starts with a
43+
list of donors.
5744

5845
.. code-block:: javascript
5946

60-
db.randomSamples.updateMany(
61-
{},
47+
db.donors.insertMany(
6248
[
63-
{ $set: { "random": { $rand: {} } } }
49+
{ donorId: 1000, amount: 0, frequency: 1 },
50+
{ donorId: 1001, amount: 0, frequency: 2 },
51+
{ donorId: 1002, amount: 0, frequency: 1 },
52+
{ donorId: 1003, amount: 0, frequency: 2 },
53+
{ donorId: 1004, amount: 0, frequency: 1 }
6454
]
6555
)
6656

67-
We can use :pipeline:`$project` to see the output. The
68-
:pipeline:`$limit` stage halts the pipeline after the third document.
57+
We use an aggregation pipeline to update each document with a random
58+
donation amount.
6959

7060
.. code-block:: javascript
7161

72-
db.randomSamples.aggregate(
62+
db.donors.aggregate(
7363
[
74-
{ $project: {_id: 0, random: 1 } },
75-
{ $limit: 3 }
76-
]
64+
{ $set: { amount: { $multiply: [ { $rand: {} }, 100 ] } } },
65+
{ $set: { amount: { $floor: "$amount" } } },
66+
{ $merge: "donors" }
67+
]
7768
)
7869

79-
The output shows the random values.
70+
The first :pipeline:`$set` stage updates the ``amount`` field. An
71+
initial value between 0 and 1 is generated using ``$rand``. Then
72+
:expression:`$multiply` scales it upward 100 times.
8073

81-
.. code-block:: javascript
82-
:copyable: false
83-
84-
{ "random" : 0.8751284485870464 }
85-
{ "random" : 0.515147067802108 }
86-
{ "random" : 0.3750004525681561 }
74+
The :expression:`$floor` operator in the second ``$set`` stage removes
75+
the decimal portion from the ``amount`` to leave an integer value.
8776

88-
Rounding to Control the Number of Output Digits
89-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77+
Finally, :pipeline:`$merge` writes the random value created in the
78+
previous steps to the ``amount`` field, updating it for each document
79+
in the ``donors`` collection.
9080

91-
If you want a shorter random value, consider using :expression:`$round`.
92-
Note that the :pipeline:`$set` stage updates the document, if ``$rand``
93-
is called in a :pipeline:`$project` stage the underlying document is
94-
not modified.
81+
You can view the results with a projection stage:
9582

9683
.. code-block:: javascript
9784

98-
db.randomSamples.aggregate(
85+
db.donors.aggregate(
9986
[
100-
{ $match: {} },
101-
{ $set: { rounded: { $round: [ "$random", 4 ] } } },
102-
{ $out: "randomSamples" }
87+
{ $project: {_id: 0, donorId: 1, amount: 1 } }
10388
]
10489
)
10590

106-
The :pipeline:`$project` stage displays the original and rounded value
107-
for each document.
108-
109-
.. code-block:: javascript
110-
111-
db.randomSamples.aggregate(
112-
[
113-
{ $project: {_id:0, random:1, rounded: 1 } },
114-
{ $limit: 3 }
115-
]
116-
)
117-
118-
The update documents look like this:
91+
The projection shows the scaled amounts are now random values in the
92+
range from 0 to 99.
11993

12094
.. code-block:: javascript
12195
:copyable: false
12296

123-
{ "random" : 0.8751284485870464, "rounded" : 0.8751 }
124-
{ "random" : 0.515147067802108, "rounded" : 0.5151 }
125-
{ "random" : 0.3750004525681561, "rounded" : 0.375 }
97+
{ "donorId" : 1000, "amount" : 27 }
98+
{ "donorId" : 1001, "amount" : 10 }
99+
{ "donorId" : 1002, "amount" : 88 }
100+
{ "donorId" : 1003, "amount" : 73 }
101+
{ "donorId" : 1004, "amount" : 5 }
126102

127-
.. note::
103+
Select Random Items From a Collection
104+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
105+
106+
You can use ``$rand`` in an aggregation pipeline to select random
107+
documents from a collection. Consider a collection of voter records:
128108

129-
Like ``$rand``, the value returned by the ``$round`` operator does
130-
not include any trailing 0s so the number of digits returned may
131-
vary.
109+
.. code-block:: javascript
132110

133-
Selecting Random Items From a Collection
134-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111+
db.voters.insertMany(
112+
[
113+
{ name: "Archibald", voterId: 4321, district: 3, registered: true },
114+
{ name: "Beckham", voterId: 4331, district: 3, registered: true },
115+
{ name: "Carolin", voterId: 5321, district: 4, registered: true },
116+
{ name: "Debarge", voterId: 4343, district: 3, registered: false },
117+
{ name: "Eckhard", voterId: 4161, district: 3, registered: false },
118+
{ name: "Faberge", voterId: 4300, district: 1, registered: true },
119+
{ name: "Grimwald", voterId: 4111, district: 3, registered: true },
120+
{ name: "Humphrey", voterId: 2021, district: 3, registered: true },
121+
{ name: "Idelfon", voterId: 1021, district: 4, registered: true },
122+
{ name: "Justo", voterId: 9891, district: 3, registered: false }
123+
]
124+
)
135125

136-
The ``$rand`` operator can be used in an aggregation pipeline to select
137-
random documents from a collection. In this example we use ``$rand`` to
138-
select about half the documents in the ``randomSamples`` collection.
126+
Imagine you want to select about half of the voters in District 3 to do
127+
some polling.
139128

140129
.. code-block:: javascript
141130

142-
db.randomSamples.aggregate(
131+
db.voters.aggregate(
143132
[
133+
{ $match: { district: 3 } },
144134
{ $match: { $expr: { $lt: [0.5, {$rand: {} } ] } } },
145-
{ $count: "numMatches" }
135+
{ $project: { _id: 0, name: 1, registered: 1 } }
146136
]
147137
)
148138

149-
There are 100 documents in ``randomSamples``. Running the sample code 5
150-
times produces the following output which approaches the expected value
151-
of 50 matches in a collection this size.
152-
139+
The first pipeline stage matches all documents where the voter is from
140+
district 3.
141+
142+
The second :pipeline:`$match` stage uses ``$rand`` in a match
143+
expression to further refine the selection. For each document,
144+
``$rand`` generates a value between 0 and 1. The threshhold of ``0.5``
145+
in the less than :expression:`($lt)<$lt>` comparison means that
146+
:query:`$expr` will be true for about half the documents.
147+
148+
In the :pipeline:`$project` stage the selected documents are filtered
149+
to return the ``name`` and ``registered`` fields. There are 7 voters in
150+
District 3, running the code selects about half of them.
151+
153152
.. code-block:: javascript
154153
:copyable: false
155154

156-
{ "numMatches" : 49 }
157-
{ "numMatches" : 52 }
158-
{ "numMatches" : 54 }
159-
{ "numMatches" : 48 }
160-
{ "numMatches" : 59 }
155+
{ "name" : "Archibald", "registered" : true }
156+
{ "name" : "Debarge", "registered" : false }
157+
{ "name" : "Humphrey", "registered" : true }
161158

162159
.. note::
163160

164-
This example shows that the number of documents selected is
165-
different each time. If you need to select an exact number of
166-
documents, consider using :pipeline:`$sample` instead of ``$rand``.
161+
The number of documents selected is different each time. If you need
162+
to select an exact number of documents, consider using
163+
:pipeline:`$sample` instead of ``$rand``.
167164

168165
.. seealso::
169166

source/reference/operator/query/rand.txt

Lines changed: 97 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,115 @@ Definition
2626
Examples
2727
--------
2828

29-
This code creates a small collection of 100 documents. We will
30-
use ``$rand`` to select random documents from the collection.
29+
Generate Random Data Points
30+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
31+
32+
This example models charitable donations. The collection starts with a
33+
list of donors.
34+
35+
.. code-block:: javascript
36+
37+
db.donors.insertMany(
38+
[
39+
{ donorId: 1000, amount: 0, frequency: 1 },
40+
{ donorId: 1001, amount: 0, frequency: 2 },
41+
{ donorId: 1002, amount: 0, frequency: 1 },
42+
{ donorId: 1003, amount: 0, frequency: 2 },
43+
{ donorId: 1004, amount: 0, frequency: 1 }
44+
]
45+
)
46+
47+
Then we construct an operation to update each document with a random
48+
donation amount:
3149

3250
.. code-block:: javascript
3351

34-
N = 100
35-
bulk = db.samples.initializeUnorderedBulkOp()
36-
for (i = 0; i < N; i++) { bulk.insert({_id: i, r: 0}) }
37-
bulk.execute()
52+
db.donors.updateMany(
53+
{},
54+
[
55+
{ $set:
56+
{ amount:
57+
{ $floor:
58+
{ $multiply: [ { $rand: {} }, 100 ] }
59+
}
60+
}
61+
}
62+
]
63+
)
3864

39-
In this example we use ``$rand`` to select about half the documents.
65+
The empty update filter matches every document in the collection.
66+
67+
For each document we generate a value between 0 and 1 using ``$rand``
68+
then scale the value with :expression:`$multiply`.
69+
70+
The :expression:`$floor` operator removes the decimal portion so the
71+
updated ``amount`` is an integer value.
72+
73+
After updating the collection, the documents look like this:
4074

4175
.. code-block:: javascript
76+
:copyable: false
77+
78+
{ "donorId" : 1000, "amount" : 2, "frequency" : 1 }
79+
{ "donorId" : 1001, "amount" : 58, "frequency" : 2 }
80+
{ "donorId" : 1002, "amount" : 27, "frequency" : 1 }
81+
{ "donorId" : 1003, "amount" : 26, "frequency" : 2 }
82+
{ "donorId" : 1004, "amount" : 42, "frequency" : 1 }
83+
84+
Select Random Items From a Collection
85+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
86+
87+
The ``$rand`` operator can be used to select random documents from a
88+
collection. Given a collection of voter records:
89+
90+
.. code-block:: javascript
91+
92+
db.voters.insertMany(
93+
[
94+
{ name: "Archibald", voterId: 4321, district: 3, registered: true },
95+
{ name: "Beckham", voterId: 4331, district: 3, registered: true },
96+
{ name: "Carolin", voterId: 5321, district: 4, registered: true },
97+
{ name: "Debarge", voterId: 4343, district: 3, registered: false },
98+
{ name: "Eckhard", voterId: 4161, district: 3, registered: false },
99+
{ name: "Faberge", voterId: 4300, district: 1, registered: true },
100+
{ name: "Grimwald", voterId: 4111, district: 3, registered: true },
101+
{ name: "Humphrey", voterId: 2021, district: 3, registered: true },
102+
{ name: "Idelfon", voterId: 1021, district: 4, registered: true },
103+
{ name: "Justo", voterId: 9891, district: 3, registered: false }
104+
]
105+
)
106+
107+
Imagine you want to select about half of the voters in District 3 to do
108+
some polling.
109+
110+
.. code-block:: javascript
111+
112+
db.voters.find(
113+
{ district: 3,
114+
$expr: { $lt: [0.5, {$rand: {} } ] }
115+
},
116+
{ _id: 0, name: 1, registered: 1 }
117+
)
118+
119+
The intial match on the ``district`` field selects documents where the
120+
voter is from district 3.
42121

43-
db.samples.find(
44-
{ $expr: { $lt: [0.5, {$rand: {} } ] } }
45-
).count()
122+
The :query:`$expr` operator uses ``$rand`` to further refine the
123+
:dbcommand:`$find` operation. For each document, ``$rand`` generates a
124+
value between 0 and 1. The threshold of ``0.5`` means the less than
125+
:expression:`($lt)<$lt>` comparison will be true for about half the
126+
documents in the set.
46127

47-
Running this :dbcommand:`find` operation five times returns five random
48-
values that approach the number 50, which is the expected value for a
49-
collection of this size. For example:
128+
There are 7 voters in District 3, running the code selects about half
129+
of them.
50130

51131
.. code-block:: javascript
52132
:copyable: false
53133

54-
51
55-
53
56-
49
57-
45
58-
47
134+
{ "name" : "Beckham", "registered" : true }
135+
{ "name" : "Eckhard", "registered" : false }
136+
{ "name" : "Grimwald", "registered" : true }
137+
{ "name" : "Humphrey", "registered" : true }
59138

60139
.. seealso::
61140

0 commit comments

Comments
 (0)