.\" This manpage is Copyright (C) 2017 MongoDB, Inc. .\" .\" Permission is granted to copy, distribute and/or modify this document .\" under the terms of the GNU Free Documentation License, Version 1.3 .\" or any later version published by the Free Software Foundation; .\" with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. .\" A copy of the license is included in the section entitled "GNU .\" Free Documentation License". .\" .TH "BASIC_AGGREGATION_EXAMPLES" "3" "2017\(hy01\(hy30" "MongoDB C Driver" .SH NAME Basic_Aggregation_Examples \- None .SH "SETUP" First we'll write some code to insert sample data: .nf /* Don't try to compile this file on its own. It's 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 (collection, true, NULL); docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]"); docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]"); docs[2] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]"); docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]"); 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, "Error inserting data: %s\en", error.message); } mongoc_bulk_operation_destroy (bulk); return ret; } /* A helper which we'll use a lot later on */ void print_res (const bson_t* reply) { BSON_ASSERT (reply); char *str = bson_as_json (reply, NULL); printf ("%s\en", str); bson_free (str); } .fi .SH "DISTINCT COMMAND" This is how to use the .B distinct command to get the distinct values of .B x which are greater than .B 1 : .nf 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 ("distinct", BCON_UTF8 (COLLECTION_NAME), "key", BCON_UTF8 ("x"), "query", "{", "x", "{", "$gt", BCON_DOUBLE (1.0), "}", "}" ); res = mongoc_database_command_simple (database, command, NULL, &reply, &error); if (!res) { fprintf (stderr, "Error with distinct: %s\en", error.message); goto cleanup; } /* Do something with reply (in this case iterate through the values) */ if (!(bson_iter_init_find (&iter, &reply, "values") && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &array_iter))) { fprintf (stderr, "Couldn't extract \e"values\e" field from response\en"); goto cleanup; } while (bson_iter_next (&array_iter)) { if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) { val = bson_iter_double (&array_iter); printf ("Next double: %f\en", val); } } cleanup: /* cleanup */ bson_destroy (command); bson_destroy (&reply); return res; } .fi .SH "MAPREDUCE - BASIC EXAMPLE" A simple example using the map reduce framework. It simply adds up the number of occurrences of each "tag". First define the .B map and .B reduce functions: .nf const char* const COLLECTION_NAME = "things"; /* Our map function just emits a single (key, 1) pair for each tag in the array: */ const char* const MAPPER = "function () {" "this.tags.forEach(function(z) {" "emit(z, 1);" "});" "}"; /* The reduce function sums over all of the emitted values for a given key: */ const char* const REDUCER = "function (key, values) {" "var total = 0;" "for (var i = 0; i < values.length; i++) {" "total += values[i];" "}" "return total;" "}"; /* Note We can’t just return values.length as the reduce function might be called iteratively on the results of other reduce steps. */ .fi Run the .B mapReduce command: .nf bool map_reduce_basic (mongoc_database_t* database) { bson_t reply; bson_t* command; bool res; bson_error_t error; mongoc_cursor_t* cursor; const bson_t* doc; bool map_reduce_done = false; bool query_done = false; const char* out_collection_name = "outCollection"; mongoc_collection_t* out_collection; /* Empty find query */ bson_t find_query = BSON_INITIALIZER; /* Construct the mapReduce command */ /* Other arguments can also be specified here, like "query" or "limit" and so on */ command = BCON_NEW ("mapReduce", BCON_UTF8 (COLLECTION_NAME), "map", BCON_CODE (MAPPER), "reduce", BCON_CODE (REDUCER), "out", BCON_UTF8 (out_collection_name)); res = mongoc_database_command_simple (database, command, NULL, &reply, &error); map_reduce_done = true; if (!res) { fprintf (stderr, "MapReduce failed: %s\en", error.message); goto cleanup; } /* Do something with the reply (it doesn't contain the mapReduce results) */ print_res (&reply); /* Now we'll 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 */ while (mongoc_cursor_next (cursor, &doc)) { print_res (doc); } if (mongoc_cursor_error (cursor, &error)) { fprintf (stderr, "ERROR: %s\en", error.message); res = false; goto cleanup; } cleanup: /* cleanup */ if (query_done) { mongoc_cursor_destroy (cursor); mongoc_collection_destroy (out_collection); } if (map_reduce_done) { bson_destroy (&reply); bson_destroy (command); } return res; } .fi .SH "MAPREDUCE - MORE COMPLICATED EXAMPLE" You must have replica set running for this. In this example we contact a secondary in the replica set and do an "inline" map reduce, so the results are returned immediately: .nf 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 "query" or "limit" and so on */ /* Read the results inline from a secondary replica */ command = BCON_NEW ("mapReduce", BCON_UTF8 (COLLECTION_NAME), "map", BCON_CODE (MAPPER), "reduce", BCON_CODE (REDUCER), "out", "{", "inline", "1", "}"); 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, "ERROR: %s\en", error.message); res = false; } mongoc_cursor_destroy (cursor); mongoc_read_prefs_destroy (read_pref); bson_destroy (command); return res; } .fi .SH "RUNNING" Here's how to run the example code .nf /* * Copyright 2016 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * 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\(hy2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" 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 "constants.c" #include "../doc\(hycommon\(hyinsert.c" #include "distinct.c" #include "map\(hyreduce\(hybasic.c" #include "map\(hyreduce\(hyadvanced.c" int main (int argc, char *argv[]) { mongoc_database_t *database = NULL; mongoc_client_t *client = NULL; mongoc_collection_t *collection = NULL; char *host_and_port = NULL; int res = 0; if (argc != 2) { fprintf (stderr, "usage: %s CONNECTION\(hySTRING\en", argv[0]); fprintf (stderr, "the connection string can be of the following forms:\en"); fprintf (stderr, "localhost\et\et\et\etlocal machine\en"); fprintf (stderr, "localhost:27018\et\et\et\etlocal machine on port 27018\en"); fprintf (stderr, "mongodb://user:pass@localhost:27017\et" "local machine on port 27017, and authenticate with username " "user and password pass\en"); return 1; } mongoc_init (); if (strncmp (argv[1], "mongodb://", 10) == 0) { host_and_port = bson_strdup (argv [1]); } else { host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]); } client = mongoc_client_new (host_and_port); if (!client) { fprintf (stderr, "Invalid hostname or port: %s\en", host_and_port); res = 2; goto cleanup; } mongoc_client_set_error_api (client, 2); database = mongoc_client_get_database (client, "test"); collection = mongoc_database_get_collection (database, COLLECTION_NAME); printf ("Inserting data\en"); if (!insert_data (collection)) { res = 3; goto cleanup; } printf ("distinct\en"); if (!distinct (database)) { res = 4; goto cleanup; } printf ("map reduce\en"); if (!map_reduce_basic (database)) { res = 5; goto cleanup; } printf ("more complicated map reduce\en"); if (!map_reduce_advanced (database)) { res = 6; goto cleanup; } cleanup: if (collection) { mongoc_collection_destroy (collection); } if (database) { mongoc_database_destroy (database); } if (client) { mongoc_client_destroy (client); } if (host_and_port) { bson_free (host_and_port); } mongoc_cleanup (); return res; } .fi 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 .B here ). Otherwise, just start an instance of MongoDB: .B $ .B mongod Now compile and run the example program: .B $ .B cd examples/basic_aggregation/ .B $ .B gcc -Wall -o agg-example basic-aggregation.c $(pkg-config --cflags --libs libmongoc-1.0) .B $ .B ./agg-example localhost .B .SH COLOPHON This page is part of MongoDB C Driver. Please report any bugs at https://jira.mongodb.org/browse/CDRIVER.