1MONGOC_DISTINCT_MAPREDUCE(3)       libmongoc      MONGOC_DISTINCT_MAPREDUCE(3)
2
3
4
5This  document  provides  some  practical, simple, examples to demonstrate the

distinct and mapReduce commands.

7

SETUP

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

DISTINCT COMMAND

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

MAPREDUCE - BASIC EXAMPLE

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

MAPREDUCE - MORE COMPLICATED EXAMPLE

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

RUNNING THE EXAMPLES

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

AUTHOR

453       MongoDB, Inc
454
456       2017-present, MongoDB, Inc
457
458
459
460
4611.25.1                           Nov 08, 2023     MONGOC_DISTINCT_MAPREDUCE(3)
Impressum