1MONGOC_DISTINCT_MAPREDUCE(3)       libmongoc      MONGOC_DISTINCT_MAPREDUCE(3)
2
3
4

NAME

6       mongoc_distinct_mapreduce - "distinct" and "mapReduce"
7
8       This  document provides some practical, simple, examples to demonstrate
9       the distinct and mapReduce commands.
10

SETUP

12       First we'll write some code to insert sample data:
13
14       doc-common-insert.c
15
16          /* Don't try to compile this file on its own. It's meant to be #included
17             by example code */
18
19          /* Insert some sample data */
20          bool
21          insert_data (mongoc_collection_t *collection)
22          {
23             mongoc_bulk_operation_t *bulk;
24             enum N { ndocs = 4 };
25             bson_t *docs[ndocs];
26             bson_error_t error;
27             int i = 0;
28             bool ret;
29
30             bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL);
31
32             docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]");
33             docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]");
34             docs[2] = BCON_NEW (
35                "x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]");
36             docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]");
37
38             for (i = 0; i < ndocs; i++) {
39                mongoc_bulk_operation_insert (bulk, docs[i]);
40                bson_destroy (docs[i]);
41                docs[i] = NULL;
42             }
43
44             ret = mongoc_bulk_operation_execute (bulk, NULL, &error);
45
46             if (!ret) {
47                fprintf (stderr, "Error inserting data: %s\n", error.message);
48             }
49
50             mongoc_bulk_operation_destroy (bulk);
51             return ret;
52          }
53
54          /* A helper which we'll use a lot later on */
55          void
56          print_res (const bson_t *reply)
57          {
58             char *str;
59             BSON_ASSERT (reply);
60             str = bson_as_canonical_extended_json (reply, NULL);
61             printf ("%s\n", str);
62             bson_free (str);
63          }
64
65

DISTINCT COMMAND

67       This is how to use the distinct command to get the distinct values of x
68       which are greater than 1:
69
70       distinct.c
71
72          bool
73          distinct (mongoc_database_t *database)
74          {
75             bson_t *command;
76             bson_t reply;
77             bson_error_t error;
78             bool res;
79             bson_iter_t iter;
80             bson_iter_t array_iter;
81             double val;
82
83             command = BCON_NEW ("distinct",
84                                 BCON_UTF8 (COLLECTION_NAME),
85                                 "key",
86                                 BCON_UTF8 ("x"),
87                                 "query",
88                                 "{",
89                                 "x",
90                                 "{",
91                                 "$gt",
92                                 BCON_DOUBLE (1.0),
93                                 "}",
94                                 "}");
95             res =
96                mongoc_database_command_simple (database, command, NULL, &reply, &error);
97             if (!res) {
98                fprintf (stderr, "Error with distinct: %s\n", error.message);
99                goto cleanup;
100             }
101
102             /* Do something with reply (in this case iterate through the values) */
103             if (!(bson_iter_init_find (&iter, &reply, "values") &&
104                   BSON_ITER_HOLDS_ARRAY (&iter) &&
105                   bson_iter_recurse (&iter, &array_iter))) {
106                fprintf (stderr, "Couldn't extract \"values\" field from response\n");
107                goto cleanup;
108             }
109
110             while (bson_iter_next (&array_iter)) {
111                if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) {
112                   val = bson_iter_double (&array_iter);
113                   printf ("Next double: %f\n", val);
114                }
115             }
116
117          cleanup:
118             /* cleanup */
119             bson_destroy (command);
120             bson_destroy (&reply);
121             return res;
122          }
123
124

MAPREDUCE - BASIC EXAMPLE

126       A  simple example using the map reduce framework. It simply adds up the
127       number of occurrences of each "tag".
128
129       First define the map and reduce functions:
130
131       constants.c
132
133          const char *const COLLECTION_NAME = "things";
134
135          /* Our map function just emits a single (key, 1) pair for each tag
136             in the array: */
137          const char *const MAPPER = "function () {"
138                                     "this.tags.forEach(function(z) {"
139                                     "emit(z, 1);"
140                                     "});"
141                                     "}";
142
143          /* The reduce function sums over all of the emitted values for a
144             given key: */
145          const char *const REDUCER = "function (key, values) {"
146                                      "var total = 0;"
147                                      "for (var i = 0; i < values.length; i++) {"
148                                      "total += values[i];"
149                                      "}"
150                                      "return total;"
151                                      "}";
152          /* Note We can't just return values.length as the reduce function
153             might be called iteratively on the results of other reduce
154             steps. */
155
156
157       Run the mapReduce command. Use the generic command helpers  (e.g.  mon‐
158       goc_database_command_simple()).   Do not the read command helpers (e.g.
159       mongoc_database_read_command_with_opts()) because they  are  considered
160       retryable read operations. If retryable reads are enabled, those opera‐
161       tions will retry once on a retryable error, giving undesirable behavior
162       for mapReduce.
163
164       map-reduce-basic.c
165
166          bool
167          map_reduce_basic (mongoc_database_t *database)
168          {
169             bson_t reply;
170             bson_t *command;
171             bool res;
172             bson_error_t error;
173             mongoc_cursor_t *cursor;
174             const bson_t *doc;
175
176             bool query_done = false;
177
178             const char *out_collection_name = "outCollection";
179             mongoc_collection_t *out_collection;
180
181             /* Empty find query */
182             bson_t find_query = BSON_INITIALIZER;
183
184             /* Construct the mapReduce command */
185
186             /* Other arguments can also be specified here, like "query" or
187                "limit" and so on */
188             command = BCON_NEW ("mapReduce",
189                                 BCON_UTF8 (COLLECTION_NAME),
190                                 "map",
191                                 BCON_CODE (MAPPER),
192                                 "reduce",
193                                 BCON_CODE (REDUCER),
194                                 "out",
195                                 BCON_UTF8 (out_collection_name));
196             res =
197                mongoc_database_command_simple (database, command, NULL, &reply, &error);
198
199             if (!res) {
200                fprintf (stderr, "MapReduce failed: %s\n", error.message);
201                goto cleanup;
202             }
203
204             /* Do something with the reply (it doesn't contain the mapReduce results) */
205             print_res (&reply);
206
207             /* Now we'll query outCollection to see what the results are */
208             out_collection =
209                mongoc_database_get_collection (database, out_collection_name);
210             cursor = mongoc_collection_find_with_opts (
211                out_collection, &find_query, NULL, NULL);
212             query_done = true;
213
214             /* Do something with the results */
215             while (mongoc_cursor_next (cursor, &doc)) {
216                print_res (doc);
217             }
218
219             if (mongoc_cursor_error (cursor, &error)) {
220                fprintf (stderr, "ERROR: %s\n", error.message);
221                res = false;
222                goto cleanup;
223             }
224
225          cleanup:
226             /* cleanup */
227             if (query_done) {
228                mongoc_cursor_destroy (cursor);
229                mongoc_collection_destroy (out_collection);
230             }
231
232             bson_destroy (&reply);
233             bson_destroy (command);
234
235             return res;
236          }
237
238

MAPREDUCE - MORE COMPLICATED EXAMPLE

240       You must have replica set running for this.
241
242       In  this  example  we  contact a secondary in the replica set and do an
243       "inline" map reduce, so the results are returned immediately:
244
245       map-reduce-advanced.c
246
247          bool
248          map_reduce_advanced (mongoc_database_t *database)
249          {
250             bson_t *command;
251             bson_error_t error;
252             bool res = true;
253             mongoc_cursor_t *cursor;
254             mongoc_read_prefs_t *read_pref;
255             const bson_t *doc;
256
257             /* Construct the mapReduce command */
258             /* Other arguments can also be specified here, like "query" or "limit"
259                and so on */
260
261             /* Read the results inline from a secondary replica */
262             command = BCON_NEW ("mapReduce",
263                                 BCON_UTF8 (COLLECTION_NAME),
264                                 "map",
265                                 BCON_CODE (MAPPER),
266                                 "reduce",
267                                 BCON_CODE (REDUCER),
268                                 "out",
269                                 "{",
270                                 "inline",
271                                 "1",
272                                 "}");
273
274             read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
275             cursor = mongoc_database_command (
276                database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref);
277
278             /* Do something with the results */
279             while (mongoc_cursor_next (cursor, &doc)) {
280                print_res (doc);
281             }
282
283             if (mongoc_cursor_error (cursor, &error)) {
284                fprintf (stderr, "ERROR: %s\n", error.message);
285                res = false;
286             }
287
288             mongoc_cursor_destroy (cursor);
289             mongoc_read_prefs_destroy (read_pref);
290             bson_destroy (command);
291
292             return res;
293          }
294
295

RUNNING THE EXAMPLES

297       Here's how to run the example code
298
299       basic-aggregation.c
300
301          /*
302           * Copyright 2016 MongoDB, Inc.
303           *
304           * Licensed under the Apache License, Version 2.0 (the "License");
305           * you may not use this file except in compliance with the License.
306           * You may obtain a copy of the License at
307           *
308           *   http://www.apache.org/licenses/LICENSE-2.0
309           *
310           * Unless required by applicable law or agreed to in writing, software
311           * distributed under the License is distributed on an "AS IS" BASIS,
312           * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
313           * See the License for the specific language governing permissions and
314           * limitations under the License.
315           */
316
317
318          #include <mongoc/mongoc.h>
319          #include <stdio.h>
320
321
322          #include "constants.c"
323
324          #include "../doc-common-insert.c"
325          #include "distinct.c"
326          #include "map-reduce-basic.c"
327          #include "map-reduce-advanced.c"
328
329
330          int
331          main (int argc, char *argv[])
332          {
333             mongoc_database_t *database = NULL;
334             mongoc_client_t *client = NULL;
335             mongoc_collection_t *collection = NULL;
336             mongoc_uri_t *uri = NULL;
337             bson_error_t error;
338             char *host_and_port = NULL;
339             int exit_code = EXIT_FAILURE;
340
341             if (argc != 2) {
342                fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]);
343                fprintf (stderr,
344                         "the connection string can be of the following forms:\n");
345                fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
346                fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
347                fprintf (stderr,
348                         "mongodb://user:pass@localhost:27017\t"
349                         "local machine on port 27017, and authenticate with username "
350                         "user and password pass\n");
351                return exit_code;
352             }
353
354             mongoc_init ();
355
356             if (strncmp (argv[1], "mongodb://", 10) == 0) {
357                host_and_port = bson_strdup (argv[1]);
358             } else {
359                host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]);
360             }
361
362             uri = mongoc_uri_new_with_error (host_and_port, &error);
363             if (!uri) {
364                fprintf (stderr,
365                         "failed to parse URI: %s\n"
366                         "error message:       %s\n",
367                         host_and_port,
368                         error.message);
369                goto cleanup;
370             }
371
372             client = mongoc_client_new_from_uri (uri);
373             if (!client) {
374                goto cleanup;
375             }
376
377             mongoc_client_set_error_api (client, 2);
378             database = mongoc_client_get_database (client, "test");
379             collection = mongoc_database_get_collection (database, COLLECTION_NAME);
380
381             printf ("Inserting data\n");
382             if (!insert_data (collection)) {
383                goto cleanup;
384             }
385
386             printf ("distinct\n");
387             if (!distinct (database)) {
388                goto cleanup;
389             }
390
391             printf ("map reduce\n");
392             if (!map_reduce_basic (database)) {
393                goto cleanup;
394             }
395
396             printf ("more complicated map reduce\n");
397             if (!map_reduce_advanced (database)) {
398                goto cleanup;
399             }
400
401             exit_code = EXIT_SUCCESS;
402
403          cleanup:
404             if (collection) {
405                mongoc_collection_destroy (collection);
406             }
407
408             if (database) {
409                mongoc_database_destroy (database);
410             }
411
412             if (client) {
413                mongoc_client_destroy (client);
414             }
415
416             if (uri) {
417                mongoc_uri_destroy (uri);
418             }
419
420             if (host_and_port) {
421                bson_free (host_and_port);
422             }
423
424             mongoc_cleanup ();
425             return exit_code;
426          }
427
428
429       If you want to try the advanced map reduce example  with  a  secondary,
430       start  a  replica  set  (instructions  for  how to do this can be found
431       here).
432
433       Otherwise, just start an instance of MongoDB:
434
435          $ mongod
436
437       Now compile and run the example program:
438
439          $ cd examples/basic_aggregation/
440          $ gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0)
441          $ ./agg-example localhost
442
443          Inserting data
444          distinct
445          Next double: 2.000000
446          Next double: 3.000000
447          map reduce
448          { "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
449          { "_id" : "cat", "value" : 63 }
450          { "_id" : "dog", "value" : 42 }
451          { "_id" : "mouse", "value" : 21 }
452          more complicated map reduce
453          { "results" : [ { "_id" : "cat", "value" : 63 }, { "_id" : "dog", "value" : 42 }, { "_id" : "mouse", "value" : 21 } ], "timeMillis" : 14, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
454

AUTHOR

456       MongoDB, Inc
457
459       2017-present, MongoDB, Inc
460
461
462
463
4641.21.1                           Mar 02, 2022     MONGOC_DISTINCT_MAPREDUCE(3)
Impressum