.\" Man page generated from reStructuredText. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "MONGOC_DISTINCT_MAPREDUCE" "3" "May 07, 2024" "1.27.1" "libmongoc" .sp This document provides some practical, simple, examples to demonstrate the \fBdistinct\fP and \fBmapReduce\fP commands. .SH SETUP .sp First we\(aqll write some code to insert sample data: .sp doc\-common\-insert.c .INDENT 0.0 .INDENT 3.5 .sp .EX /* Don\(aqt try to compile this file on its own. It\(aqs meant to be #included by example code */ /* Insert some sample data */ bool insert_data (mongoc_collection_t *collection) { mongoc_bulk_operation_t *bulk; enum N { ndocs = 4 }; bson_t *docs[ndocs]; bson_error_t error; int i = 0; bool ret; bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL); docs[0] = BCON_NEW (\(dqx\(dq, BCON_DOUBLE (1.0), \(dqtags\(dq, \(dq[\(dq, \(dqdog\(dq, \(dqcat\(dq, \(dq]\(dq); docs[1] = BCON_NEW (\(dqx\(dq, BCON_DOUBLE (2.0), \(dqtags\(dq, \(dq[\(dq, \(dqcat\(dq, \(dq]\(dq); docs[2] = BCON_NEW (\(dqx\(dq, BCON_DOUBLE (2.0), \(dqtags\(dq, \(dq[\(dq, \(dqmouse\(dq, \(dqcat\(dq, \(dqdog\(dq, \(dq]\(dq); docs[3] = BCON_NEW (\(dqx\(dq, BCON_DOUBLE (3.0), \(dqtags\(dq, \(dq[\(dq, \(dq]\(dq); for (i = 0; i < ndocs; i++) { mongoc_bulk_operation_insert (bulk, docs[i]); bson_destroy (docs[i]); docs[i] = NULL; } ret = mongoc_bulk_operation_execute (bulk, NULL, &error); if (!ret) { fprintf (stderr, \(dqError inserting data: %s\en\(dq, error.message); } mongoc_bulk_operation_destroy (bulk); return ret; } /* A helper which we\(aqll use a lot later on */ void print_res (const bson_t *reply) { char *str; BSON_ASSERT (reply); str = bson_as_canonical_extended_json (reply, NULL); printf (\(dq%s\en\(dq, str); bson_free (str); } .EE .UNINDENT .UNINDENT .SH "DISTINCT" COMMAND .sp This is how to use the \fBdistinct\fP command to get the distinct values of \fBx\fP which are greater than \fB1\fP: .sp distinct.c .INDENT 0.0 .INDENT 3.5 .sp .EX bool distinct (mongoc_database_t *database) { bson_t *command; bson_t reply; bson_error_t error; bool res; bson_iter_t iter; bson_iter_t array_iter; double val; command = BCON_NEW (\(dqdistinct\(dq, BCON_UTF8 (COLLECTION_NAME), \(dqkey\(dq, BCON_UTF8 (\(dqx\(dq), \(dqquery\(dq, \(dq{\(dq, \(dqx\(dq, \(dq{\(dq, \(dq$gt\(dq, BCON_DOUBLE (1.0), \(dq}\(dq, \(dq}\(dq); res = mongoc_database_command_simple (database, command, NULL, &reply, &error); if (!res) { fprintf (stderr, \(dqError with distinct: %s\en\(dq, error.message); goto cleanup; } /* Do something with reply (in this case iterate through the values) */ if (!(bson_iter_init_find (&iter, &reply, \(dqvalues\(dq) && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &array_iter))) { fprintf (stderr, \(dqCouldn\(aqt extract \e\(dqvalues\e\(dq field from response\en\(dq); goto cleanup; } while (bson_iter_next (&array_iter)) { if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) { val = bson_iter_double (&array_iter); printf (\(dqNext double: %f\en\(dq, val); } } cleanup: /* cleanup */ bson_destroy (command); bson_destroy (&reply); return res; } .EE .UNINDENT .UNINDENT .SH "MAPREDUCE" - BASIC EXAMPLE .sp A simple example using the map reduce framework. It simply adds up the number of occurrences of each \(dqtag\(dq. .sp First define the \fBmap\fP and \fBreduce\fP functions: .sp constants.c .INDENT 0.0 .INDENT 3.5 .sp .EX const char *const COLLECTION_NAME = \(dqthings\(dq; /* Our map function just emits a single (key, 1) pair for each tag in the array: */ const char *const MAPPER = \(dqfunction () {\(dq \(dqthis.tags.forEach(function(z) {\(dq \(dqemit(z, 1);\(dq \(dq});\(dq \(dq}\(dq; /* The reduce function sums over all of the emitted values for a given key: */ const char *const REDUCER = \(dqfunction (key, values) {\(dq \(dqvar total = 0;\(dq \(dqfor (var i = 0; i < values.length; i++) {\(dq \(dqtotal += values[i];\(dq \(dq}\(dq \(dqreturn total;\(dq \(dq}\(dq; /* Note We can\(aqt just return values.length as the reduce function might be called iteratively on the results of other reduce steps. */ .EE .UNINDENT .UNINDENT .sp Run the \fBmapReduce\fP command. Use the generic command helpers (e.g. \fI\%mongoc_database_command_simple()\fP). Do not the read command helpers (e.g. \fI\%mongoc_database_read_command_with_opts()\fP) because they are considered retryable read operations. If retryable reads are enabled, those operations will retry once on a retryable error, giving undesirable behavior for \fBmapReduce\fP\&. .sp map\-reduce\-basic.c .INDENT 0.0 .INDENT 3.5 .sp .EX bool map_reduce_basic (mongoc_database_t *database) { bson_t reply; bool res = false; bson_error_t error; mongoc_cursor_t *cursor = NULL; bool query_done = false; const char *out_collection_name = \(dqoutCollection\(dq; mongoc_collection_t *out_collection = NULL; /* Empty find query */ bson_t find_query = BSON_INITIALIZER; /* Construct the mapReduce command */ /* Other arguments can also be specified here, like \(dqquery\(dq or \(dqlimit\(dq and so on */ bson_t *const command = BCON_NEW (\(dqmapReduce\(dq, BCON_UTF8 (COLLECTION_NAME), \(dqmap\(dq, BCON_CODE (MAPPER), \(dqreduce\(dq, BCON_CODE (REDUCER), \(dqout\(dq, BCON_UTF8 (out_collection_name)); res = mongoc_database_command_simple (database, command, NULL, &reply, &error); if (!res) { fprintf (stderr, \(dqMapReduce failed: %s\en\(dq, error.message); goto cleanup; } /* Do something with the reply (it doesn\(aqt contain the mapReduce results) */ print_res (&reply); /* Now we\(aqll query outCollection to see what the results are */ out_collection = mongoc_database_get_collection (database, out_collection_name); cursor = mongoc_collection_find_with_opts (out_collection, &find_query, NULL, NULL); query_done = true; /* Do something with the results */ const bson_t *doc = NULL; while (mongoc_cursor_next (cursor, &doc)) { print_res (doc); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, \(dqERROR: %s\en\(dq, error.message); res = false; goto cleanup; } cleanup: /* cleanup */ if (query_done) { mongoc_cursor_destroy (cursor); mongoc_collection_destroy (out_collection); } bson_destroy (&reply); bson_destroy (command); return res; } .EE .UNINDENT .UNINDENT .SH "MAPREDUCE" - MORE COMPLICATED EXAMPLE .sp You must have replica set running for this. .sp In this example we contact a secondary in the replica set and do an \(dqinline\(dq map reduce, so the results are returned immediately: .sp map\-reduce\-advanced.c .INDENT 0.0 .INDENT 3.5 .sp .EX bool map_reduce_advanced (mongoc_database_t *database) { bson_t *command; bson_error_t error; bool res = true; mongoc_cursor_t *cursor; mongoc_read_prefs_t *read_pref; const bson_t *doc; /* Construct the mapReduce command */ /* Other arguments can also be specified here, like \(dqquery\(dq or \(dqlimit\(dq and so on */ /* Read the results inline from a secondary replica */ command = BCON_NEW (\(dqmapReduce\(dq, BCON_UTF8 (COLLECTION_NAME), \(dqmap\(dq, BCON_CODE (MAPPER), \(dqreduce\(dq, BCON_CODE (REDUCER), \(dqout\(dq, \(dq{\(dq, \(dqinline\(dq, \(dq1\(dq, \(dq}\(dq); read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); cursor = mongoc_database_command (database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref); /* Do something with the results */ while (mongoc_cursor_next (cursor, &doc)) { print_res (doc); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, \(dqERROR: %s\en\(dq, error.message); res = false; } mongoc_cursor_destroy (cursor); mongoc_read_prefs_destroy (read_pref); bson_destroy (command); return res; } .EE .UNINDENT .UNINDENT .SH RUNNING THE EXAMPLES .sp Here\(aqs how to run the example code .sp basic\-aggregation.c .INDENT 0.0 .INDENT 3.5 .sp .EX /* * Copyright 2016 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the \(dqLicense\(dq); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE\-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an \(dqAS IS\(dq BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include \(dqconstants.c\(dq #include \(dq../doc\-common\-insert.c\(dq #include \(dqdistinct.c\(dq #include \(dqmap\-reduce\-basic.c\(dq #include \(dqmap\-reduce\-advanced.c\(dq int main (int argc, char *argv[]) { mongoc_database_t *database = NULL; mongoc_client_t *client = NULL; mongoc_collection_t *collection = NULL; mongoc_uri_t *uri = NULL; bson_error_t error; char *host_and_port = NULL; int exit_code = EXIT_FAILURE; if (argc != 2) { fprintf (stderr, \(dqusage: %s CONNECTION\-STRING\en\(dq, argv[0]); fprintf (stderr, \(dqthe connection string can be of the following forms:\en\(dq); fprintf (stderr, \(dqlocalhost\et\et\et\etlocal machine\en\(dq); fprintf (stderr, \(dqlocalhost:27018\et\et\et\etlocal machine on port 27018\en\(dq); fprintf (stderr, \(dqmongodb://user:pass@localhost:27017\et\(dq \(dqlocal machine on port 27017, and authenticate with username \(dq \(dquser and password pass\en\(dq); return exit_code; } mongoc_init (); if (strncmp (argv[1], \(dqmongodb://\(dq, 10) == 0) { host_and_port = bson_strdup (argv[1]); } else { host_and_port = bson_strdup_printf (\(dqmongodb://%s\(dq, argv[1]); } uri = mongoc_uri_new_with_error (host_and_port, &error); if (!uri) { fprintf (stderr, \(dqfailed to parse URI: %s\en\(dq \(dqerror message: %s\en\(dq, host_and_port, error.message); goto cleanup; } client = mongoc_client_new_from_uri (uri); if (!client) { goto cleanup; } mongoc_client_set_error_api (client, 2); database = mongoc_client_get_database (client, \(dqtest\(dq); collection = mongoc_database_get_collection (database, COLLECTION_NAME); printf (\(dqInserting data\en\(dq); if (!insert_data (collection)) { goto cleanup; } printf (\(dqdistinct\en\(dq); if (!distinct (database)) { goto cleanup; } printf (\(dqmap reduce\en\(dq); if (!map_reduce_basic (database)) { goto cleanup; } printf (\(dqmore complicated map reduce\en\(dq); if (!map_reduce_advanced (database)) { goto cleanup; } exit_code = EXIT_SUCCESS; cleanup: if (collection) { mongoc_collection_destroy (collection); } if (database) { mongoc_database_destroy (database); } if (client) { mongoc_client_destroy (client); } if (uri) { mongoc_uri_destroy (uri); } if (host_and_port) { bson_free (host_and_port); } mongoc_cleanup (); return exit_code; } .EE .UNINDENT .UNINDENT .sp If you want to try the advanced map reduce example with a secondary, start a replica set (instructions for how to do this can be found \fI\%here\fP). .sp Otherwise, just start an instance of MongoDB: .INDENT 0.0 .INDENT 3.5 .sp .EX $ mongod .EE .UNINDENT .UNINDENT .sp Now compile and run the example program: .INDENT 0.0 .INDENT 3.5 .sp .EX $ cd examples/basic_aggregation/ $ gcc \-Wall \-o agg\-example basic\-aggregation.c $(pkg\-config \-\-cflags \-\-libs libmongoc\-1.0) $ ./agg\-example localhost Inserting data distinct Next double: 2.000000 Next double: 3.000000 map reduce { \(dqresult\(dq : \(dqoutCollection\(dq, \(dqtimeMillis\(dq : 155, \(dqcounts\(dq : { \(dqinput\(dq : 84, \(dqemit\(dq : 126, \(dqreduce\(dq : 3, \(dqoutput\(dq : 3 }, \(dqok\(dq : 1 } { \(dq_id\(dq : \(dqcat\(dq, \(dqvalue\(dq : 63 } { \(dq_id\(dq : \(dqdog\(dq, \(dqvalue\(dq : 42 } { \(dq_id\(dq : \(dqmouse\(dq, \(dqvalue\(dq : 21 } more complicated map reduce { \(dqresults\(dq : [ { \(dq_id\(dq : \(dqcat\(dq, \(dqvalue\(dq : 63 }, { \(dq_id\(dq : \(dqdog\(dq, \(dqvalue\(dq : 42 }, { \(dq_id\(dq : \(dqmouse\(dq, \(dqvalue\(dq : 21 } ], \(dqtimeMillis\(dq : 14, \(dqcounts\(dq : { \(dqinput\(dq : 84, \(dqemit\(dq : 126, \(dqreduce\(dq : 3, \(dqoutput\(dq : 3 }, \(dqok\(dq : 1 } .EE .UNINDENT .UNINDENT .SH AUTHOR MongoDB, Inc .SH COPYRIGHT 2017-present, MongoDB, Inc .\" Generated by docutils manpage writer. .