1MongoDB::Examples(3) User Contributed Perl Documentation MongoDB::Examples(3)
2
3
4
6 MongoDB::Examples - Some examples of MongoDB syntax
7
9 version v2.2.2
10
12 For developers familiar with SQL, the following chart should help you
13 see how many common SQL queries could be expressed in MongoDB.
14
15 These are Perl-specific examples of translating SQL queries to
16 MongoDB's query language. To see the mappings for JavaScript (or
17 another language), see
18 <http://docs.mongodb.org/manual/reference/sql-comparison/>.
19
20 In the following examples, $db is a MongoDB::Database object which was
21 retrieved by using "get_database". See MongoDB::MongoClient,
22 MongoDB::Database and MongoDB::Collection for more on the methods you
23 see below.
24
25 "CREATE TABLE USERS (a Number, b Number)"
26 Implicit, can be done explicitly.
27
28 "INSERT INTO USERS VALUES(1,1)"
29 $db->get_collection( 'users' )->insert_one( { a => 1, b => 1 } );
30
31 "SELECT a,b FROM users"
32 $db->get_collection( 'users')->find( { } )->fields( { a => 1, b => 1 });
33
34 "SELECT * FROM users"
35 $db->get_collection( 'users' )->find;
36
37 "SELECT * FROM users WHERE age=33"
38 $db->get_collection( 'users' )->find( { age => 33 } )
39
40 "SELECT a,b FROM users WHERE age=33"
41 $db->get_collection( 'users' )->find( { age => 33 } )->fields( { a => 1, b => 1 });
42
43 "SELECT * FROM users WHERE age=33 ORDER BY name"
44 $db->get_collection( 'users' )->find( { age => 33 } )->sort( { name => 1 } );
45
46 "SELECT * FROM users WHERE age>33"
47 $db->get_collection( 'users' )->find( { age => { '$gt' => 33 } } );
48
49 "SELECT * FROM users WHERE age<33"
50 $db->get_collection( 'users' )->find( { age => { '$lt' => 33 } } );
51
52 "SELECT * FROM users WHERE name LIKE "%Joe%""
53 $db->get_collection( 'users' )->find( { name => qr/Joe/ } );
54
55 "SELECT * FROM users WHERE name LIKE "Joe%""
56 $db->get_collection( 'users' )->find( {name => qr/^Joe/ } );
57
58 "SELECT * FROM users WHERE age>33 AND age<=40"
59 $db->get_collection( 'users' )->find( { age => { '$gt' => 33, '$lte' => 40 } } );
60
61 "SELECT * FROM users ORDER BY name DESC"
62 $db->get_collection( 'users' )->find->sort( { name => -1 } );
63
64 "CREATE INDEX myindexname ON users(name)"
65 my $indexes = $db->get_collection( 'users' )->indexes;
66 $indexes->create_one( [ name => 1 ] );
67
68 "CREATE INDEX myindexname ON users(name,ts DESC)"
69 my $indexes = $db->get_collection( 'users' )->indexes;
70 $indexes->create_one( [ name => 1, ts => -1 ] );
71
72 "SELECT * FROM users WHERE a=1 and b='q'"
73 $db->get_collection( 'users' )->find( {a => 1, b => "q" } );
74
75 "SELECT * FROM users LIMIT 10 SKIP 20"
76 $db->get_collection( 'users' )->find->limit(10)->skip(20);
77
78 "SELECT * FROM users WHERE a=1 or b=2"
79 $db->get_collection( 'users' )->find( { '$or' => [ {a => 1 }, { b => 2 } ] } );
80
81 "SELECT * FROM users LIMIT 1"
82 $db->get_collection( 'users' )->find->limit(1);
83
84 "EXPLAIN SELECT * FROM users WHERE z=3"
85 $db->get_collection( 'users' )->find( { z => 3 } )->explain;
86
87 "SELECT DISTINCT last_name FROM users"
88 $db->get_collection( 'users' )->distinct( 'last_name' );
89
90 "SELECT COUNT(*y) FROM users"
91 $db->get_collection( 'users' )->count_documents;
92
93 "SELECT COUNT(*y) FROM users where age > 30"
94 $db->get_collection( 'users' )->count_documents( { "age" => { '$gt' => 30 } } );
95
96 "SELECT COUNT(age) from users"
97 $db->get_collection( 'users' )->count_documents( { age => { '$exists' => 1 } } );
98
99 "UPDATE users SET a=1 WHERE b='q'"
100 $db->get_collection( 'users' )->update_many( { b => "q" }, { '$set' => { a => 1 } } );
101
102 "UPDATE users SET a=a+2 WHERE b='q'"
103 $db->get_collection( 'users' )->update_many( { b => "q" }, { '$inc' => { a => 2 } } );
104
105 "DELETE FROM users WHERE z="abc""
106 $db->get_database( 'users' )->delete_many( { z => "abc" } );
107
109 If you do something in the MongoDB shell and you would like to
110 translate it to Perl, the best way is to run the function in the shell
111 without parentheses, which will print the source. You can then
112 generally translate the source into Perl fairly easily.
113
114 For example, suppose we want to use "db.foo.validate" in Perl. We
115 could run:
116
117 > db.foo.validate
118 function (full) {
119 var cmd = {validate:this.getName()};
120 if (typeof full == "object") {
121 Object.extend(cmd, full);
122 } else {
123 cmd.full = full;
124 }
125 var res = this._db.runCommand(cmd);
126 if (typeof res.valid == "undefined") {
127 res.valid = false;
128 var raw = res.result || res.raw;
129 if (raw) {
130 var str = "-" + tojson(raw);
131 res.valid = !(str.match(/exception/) || str.match(/corrupt/));
132 var p = /lastExtentSize:(\d+)/;
133 var r = p.exec(str);
134 if (r) {
135 res.lastExtentSize = Number(r[1]);
136 }
137 }
138 }
139 return res;
140 }
141
142 Next, we can translate the important parts into Perl:
143
144 $db->run_command( [ validate => "foo" ] );
145
146 Find-one-and-modify
147 The find-one-and-modify commands in MongoDB::Collection are similar to
148 update (or remove), but will return the modified document. They can be
149 useful for implementing queues or locks.
150
151 For example, suppose we had a list of things to do, and we wanted to
152 remove the highest-priority item for processing. We could do a find
153 and then a delete_one, but that wouldn't be atomic (a write could occur
154 between the query and the remove). Instead, we could use
155 find_one_and_delete:
156
157 my $coll = $db->get_collection('todo');
158 my $next_task = $todo->find_one_and_delete(
159 {}, # empty filter means any document
160 { sort => {priority => -1} },
161 );
162
163 This will atomically find and pop the next-highest-priority task.
164
165 See <http://www.mongodb.org/display/DOCS/findAndModify+Command> for
166 more details on find-and-modify.
167
169 The aggregation framework is MongoDB's analogy for SQL GROUP BY
170 queries, but more generic and more powerful. An invocation of the
171 aggregation framework specifies a series of stages in a pipeline to be
172 executed in order by the server. Each stage of the pipeline is drawn
173 from one of the following so-called "pipeline operators": $project,
174 $match, $limit, $skip, $unwind, $group, $sort, and $geoNear.
175
176 The aggregation framework is the preferred way of performing most
177 aggregation tasks. New in version 2.2, it has largely obviated
178 mapReduce
179 <http://docs.mongodb.org/manual/reference/command/mapReduce/#dbcmd.mapReduce>,
180 and group
181 <http://docs.mongodb.org/manual/reference/command/group/#dbcmd.group>.
182
183 See the MongoDB aggregation framework documentation for more
184 information (<http://docs.mongodb.org/manual/aggregation/>).
185
186 $match and $group
187 The $group pipeline operator is used like GROUP BY in SQL. For example,
188 suppose we have a number of local businesses stored in a "business"
189 collection. If we wanted to find the number of coffeeshops in each
190 neighborhood, we could do:
191
192 my $out = $db->get_collection('business')->aggregate(
193 [
194 {'$match' => {'type' => 'coffeeshop'}},
195 {'$group' => {'_id' => '$neighborhood', 'num_coffeshops' => {'$sum' => 1}}}
196 ]
197 );
198
199 The SQL equivalent is "SELECT neighborhood, COUNT(*) FROM business
200 GROUP BY neighborhood WHERE type = 'coffeeshop'". After executing the
201 above aggregation query, $out will contain a MongoDB::QueryResult,
202 allowing us to iterate through result documents such as the following:
203
204 (
205 {
206 '_id' => 'Soho',
207 'num_coffeshops' => 23
208 },
209 {
210 '_id' => 'Chinatown',
211 'num_coffeshops' => 14
212 },
213 {
214 '_id' => 'Upper East Side',
215 'num_coffeshops' => 10
216 },
217 {
218 '_id' => 'East Village',
219 'num_coffeshops' => 87
220 }
221 )
222
223 Note that aggregate takes an array reference as an argument. Each
224 element of the array is document which specifies a stage in the
225 aggregation pipeline. Here our aggregation query consists of a $match
226 phase followed by a $group phase. Use $match to filter the documents in
227 the collection prior to aggregation. The "_id" field in the $group
228 stage specifies the key to group by; the "$" in '$neighborhood'
229 indicates that we are referencing the name of a key. Finally, we use
230 the $sum operator to add one for every document in a particular
231 neighborhood. There are other operators, such as $avg, $max, $min,
232 $push, and $addToSet, which can be used in the $group phase and work
233 much like $sum.
234
235 $project and $unwind
236 Now let's look at a more complex example of the aggregation framework
237 that makes use of the $project and $unwind pipeline operators. Suppose
238 we have a collection called 'courses' which contains information on
239 college courses. An example document in the collection looks like this:
240
241 {
242 '_id' => 'CSCI0170',
243 'name' => 'Computer Science 17',
244 'description' => 'An Integrated Introduction to Computer Science',
245 'instructor_id' => 29823498,
246 'instructor_name' => 'A. Greenwald',
247 'students' => [
248 { 'student_id' => 91736114, 'student_name' => 'D. Storch' },
249 { 'student_id' => 89100891, 'student_name' => 'J. Rassi' }
250 ]
251 }
252
253 We wish to generate a report containing one document per student that
254 indicates the courses in which each student is enrolled. The following
255 call to "aggregate" will do the trick:
256
257 my $out = $db->get_collection('courses')->aggregate([
258 {'$unwind' => '$students'},
259 {'$project' => {
260 '_id' => 0,
261 'course' => '$_id',
262 'student_id' => '$students.student_id',
263 }
264 },
265 {'$group' => {
266 '_id' => '$student_id',
267 'courses' => {'$addToSet' => '$course'}
268 }
269 }
270 ]);
271
272 The output documents will each have a student ID number and an array of
273 the courses in which that student is enrolled:
274
275 (
276 {
277 '_id' => 91736114,
278 'courses' => ['CSCI0170', 'CSCI0220', 'APMA1650', 'HIST1230']
279 },
280 {
281 '_id' => 89100891,
282 'courses' => ['CSCI0170', 'CSCI1670', 'CSCI1690']
283 }
284 )
285
286 The $unwind stage of the aggregation query "peels off" elements of the
287 courses array one-by-one and places them in their own documents. After
288 this phase completes, there is a separate document for each (course,
289 student) pair. The $project stage then throws out unnecessary fields
290 and keeps the ones we are interested in. It also pulls the student ID
291 field out of its subdocument and creates a top-level field with the key
292 "student_id". Last, we group by student ID, using $addToSet in order to
293 add the unique courses for each student to the "courses" array.
294
295 $sort, $skip, and $limit
296 The $sort, $skip, and $limit pipeline operators work much like their
297 companion methods in MongoDB::Cursor. Returning to the previous
298 students and courses example, suppose that we were particularly
299 interested in the student with the ID that is numerically third-to-
300 highest. We could retrieve the course list for that student by adding
301 $sort, $skip, and $limit phases to the pipeline:
302
303 my $out = $db->get_collection('courses')->aggregate([
304 {'$unwind' => '$students'},
305 {'$project' => {
306 '_id' => 0,
307 'course' => '$_id',
308 'student_id' => '$students.student_id',
309 }
310 },
311 {'$group' => {
312 '_id' => '$student_id',
313 'courses' => {'$addToSet' => '$course'}
314 }
315 },
316 {'$sort' => {'_id' => -1}},
317 {'$skip' => 2},
318 {'$limit' => 1}
319 ]);
320
322 Nested Fields
323 MongoDB allows you to store deeply nested structures and then query for
324 fields within them using dot-notation. For example, suppose we have a
325 users collection with documents that look like:
326
327 {
328 "userId" => 12345,
329 "address" => {
330 "street" => "123 Main St",
331 "city" => "Springfield",
332 "state" => "MN",
333 "zip" => "43213"
334 }
335 }
336
337 If we want to query for all users from Springfield, we can do:
338
339 my $cursor = $users->find({"address.city" => "Springfield"});
340
341 This will search documents for an "address" field that is a subdocument
342 and a "city" field within the subdocument.
343
345 Positional Operator
346 In MongoDB 1.3.4 and later, you can use positional operator, "$", to
347 update elements of an array. For instance, suppose you have an array
348 of user information and you want to update a user's name.
349
350 A sample document in JavaScript:
351
352 {
353 "users" : [
354 {
355 "name" : "bill",
356 "age" : 60
357 },
358 {
359 "name" : "fred",
360 "age" : 29
361 },
362 ]
363 }
364
365 The update:
366
367 $coll->update_one({"users.name" => "fred"}, {'users.$.name' => "george"});
368
369 This will update the array so that the element containing "name" =>
370 "fred" now has "name" => "george".
371
373 · David Golden <david@mongodb.com>
374
375 · Rassi <rassi@mongodb.com>
376
377 · Mike Friedman <friedo@friedo.com>
378
379 · Kristina Chodorow <k.chodorow@gmail.com>
380
381 · Florian Ragwitz <rafl@debian.org>
382
384 This software is Copyright (c) 2020 by MongoDB, Inc.
385
386 This is free software, licensed under:
387
388 The Apache License, Version 2.0, January 2004
389
390
391
392perl v5.32.0 2020-08-18 MongoDB::Examples(3)