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

DISTINCT COMMAND

66       This is how to use the distinct command to get the distinct values of x
67       which are greater than 1: distinct.c.INDENT 0.0
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: constants.c.INDENT 0.0
127
128          const char *const COLLECTION_NAME = "things";
129
130          /* Our map function just emits a single (key, 1) pair for each tag
131             in the array: */
132          const char *const MAPPER = "function () {"
133                                     "this.tags.forEach(function(z) {"
134                                     "emit(z, 1);"
135                                     "});"
136                                     "}";
137
138          /* The reduce function sums over all of the emitted values for a
139             given key: */
140          const char *const REDUCER = "function (key, values) {"
141                                      "var total = 0;"
142                                      "for (var i = 0; i < values.length; i++) {"
143                                      "total += values[i];"
144                                      "}"
145                                      "return total;"
146                                      "}";
147          /* Note We can't just return values.length as the reduce function
148             might be called iteratively on the results of other reduce
149             steps. */
150
151
152Run  the mapReduce command. Use the generic command helpers (e.g. mongoc_data‐

base_command_simple()). Do not the read command helpers (e.g. mongoc_data‐

base_read_command_with_opts()) because they are considered retryable read

155operations. If retryable reads are enabled, those operations will  retry  once
156on   a   retryable   error,   giving   undesirable   behavior  for  mapReduce.
157map-reduce-basic.c.INDENT 0.0
158
159          bool
160          map_reduce_basic (mongoc_database_t *database)
161          {
162             bson_t reply;
163             bson_t *command;
164             bool res;
165             bson_error_t error;
166             mongoc_cursor_t *cursor;
167             const bson_t *doc;
168
169             bool query_done = false;
170
171             const char *out_collection_name = "outCollection";
172             mongoc_collection_t *out_collection;
173
174             /* Empty find query */
175             bson_t find_query = BSON_INITIALIZER;
176
177             /* Construct the mapReduce command */
178
179             /* Other arguments can also be specified here, like "query" or
180                "limit" and so on */
181             command = BCON_NEW ("mapReduce",
182                                 BCON_UTF8 (COLLECTION_NAME),
183                                 "map",
184                                 BCON_CODE (MAPPER),
185                                 "reduce",
186                                 BCON_CODE (REDUCER),
187                                 "out",
188                                 BCON_UTF8 (out_collection_name));
189             res =
190                mongoc_database_command_simple (database, command, NULL, &reply, &error);
191
192             if (!res) {
193                fprintf (stderr, "MapReduce failed: %s\n", error.message);
194                goto cleanup;
195             }
196
197             /* Do something with the reply (it doesn't contain the mapReduce results) */
198             print_res (&reply);
199
200             /* Now we'll query outCollection to see what the results are */
201             out_collection =
202                mongoc_database_get_collection (database, out_collection_name);
203             cursor = mongoc_collection_find_with_opts (
204                out_collection, &find_query, NULL, NULL);
205             query_done = true;
206
207             /* Do something with the results */
208             while (mongoc_cursor_next (cursor, &doc)) {
209                print_res (doc);
210             }
211
212             if (mongoc_cursor_error (cursor, &error)) {
213                fprintf (stderr, "ERROR: %s\n", error.message);
214                res = false;
215                goto cleanup;
216             }
217
218          cleanup:
219             /* cleanup */
220             if (query_done) {
221                mongoc_cursor_destroy (cursor);
222                mongoc_collection_destroy (out_collection);
223             }
224
225             bson_destroy (&reply);
226             bson_destroy (command);
227
228             return res;
229          }
230
231

MAPREDUCE - MORE COMPLICATED EXAMPLE

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

RUNNING THE EXAMPLES

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

AUTHOR

445       MongoDB, Inc
446
448       2017-present, MongoDB, Inc
449
450
451
452
4531.15.2                           Nov 06, 2019     MONGOC_DISTINCT_MAPREDUCE(3)
Impressum