Skip to content

Commit 77c53ce

Browse files
mungitoperritoandf-mongodb
authored andcommitted
DOCSP-13968 update $rand with new examples
1 parent eaffe6d commit 77c53ce

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
@@ -28,36 +28,115 @@ Definition
2828
Examples
2929
--------
3030

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

3452
.. code-block:: javascript
3553

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

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

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

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

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

53133
.. code-block:: javascript
54134
:copyable: false
55135

56-
51
57-
53
58-
49
59-
45
60-
47
136+
{ "name" : "Beckham", "registered" : true }
137+
{ "name" : "Eckhard", "registered" : false }
138+
{ "name" : "Grimwald", "registered" : true }
139+
{ "name" : "Humphrey", "registered" : true }
61140

62141
.. seealso::
63142

0 commit comments

Comments
 (0)