Common Tasks¶
Drivers for some other languages provide helper functions to perform certain common tasks. In the C Driver we must explicitly build commands to send to the server.
This snippet contains example code for the explain
, copydb
and cloneCollection
commands.
Setup¶
First we’ll write some code to insert sample data:
/* 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\n", 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_canonical_extended_json (reply, NULL);
printf ("%s\n", str);
bson_free (str);
}
“explain” Command¶
This is how to use the explain
command in MongoDB 3.2+:
bool
explain (mongoc_collection_t *collection)
{
bson_t *command;
bson_t reply;
bson_error_t error;
bool res;
command = BCON_NEW ("explain",
"{",
"find",
BCON_UTF8 (COLLECTION_NAME),
"filter",
"{",
"x",
BCON_INT32 (1),
"}",
"}");
res = mongoc_collection_command_simple (
collection, command, NULL, &reply, &error);
if (!res) {
fprintf (stderr, "Error with explain: %s\n", error.message);
goto cleanup;
}
/* Do something with the reply */
print_res (&reply);
cleanup:
bson_destroy (&reply);
bson_destroy (command);
return res;
}
“copydb” Command¶
This example requires two instances of mongo to be running.
Here’s how to use the copydb
command to copy a database from another instance of MongoDB:
bool
copydb (mongoc_client_t *client, const char *other_host_and_port)
{
mongoc_database_t *admindb;
bson_t *command;
bson_t reply;
bson_error_t error;
bool res;
BSON_ASSERT (other_host_and_port);
/* Must do this from the admin db */
admindb = mongoc_client_get_database (client, "admin");
command = BCON_NEW ("copydb",
BCON_INT32 (1),
"fromdb",
BCON_UTF8 ("test"),
"todb",
BCON_UTF8 ("test2"),
/* If you want from a different host */
"fromhost",
BCON_UTF8 (other_host_and_port));
res =
mongoc_database_command_simple (admindb, command, NULL, &reply, &error);
if (!res) {
fprintf (stderr, "Error with copydb: %s\n", error.message);
goto cleanup;
}
/* Do something with the reply */
print_res (&reply);
cleanup:
bson_destroy (&reply);
bson_destroy (command);
mongoc_database_destroy (admindb);
return res;
}
“cloneCollection” Command¶
This example requires two instances of mongo to be running.
Here’s an example of the cloneCollection
command to clone a collection from another instance of MongoDB:
bool
clone_collection (mongoc_database_t *database, const char *other_host_and_port)
{
bson_t *command;
bson_t reply;
bson_error_t error;
bool res;
BSON_ASSERT (other_host_and_port);
command = BCON_NEW ("cloneCollection",
BCON_UTF8 ("test.remoteThings"),
"from",
BCON_UTF8 (other_host_and_port),
"query",
"{",
"x",
BCON_INT32 (1),
"}");
res =
mongoc_database_command_simple (database, command, NULL, &reply, &error);
if (!res) {
fprintf (stderr, "Error with clone: %s\n", error.message);
goto cleanup;
}
/* Do something with the reply */
print_res (&reply);
cleanup:
bson_destroy (&reply);
bson_destroy (command);
return res;
}
Running the Examples¶
/*
* 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-2.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 <mongoc.h>
#include <stdio.h>
const char *COLLECTION_NAME = "things";
#include "../doc-common-insert.c"
#include "explain.c"
#include "copydb.c"
#include "clone-collection.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;
int res = 0;
char *other_host_and_port = NULL;
if (argc < 2 || argc > 3) {
fprintf (stderr,
"usage: %s MONGOD-1-CONNECTION-STRING "
"[MONGOD-2-HOST-NAME:MONGOD-2-PORT]\n",
argv[0]);
fprintf (stderr,
"MONGOD-1-CONNECTION-STRING can be "
"of the following forms:\n");
fprintf (stderr, "localhost\t\t\t\tlocal machine\n");
fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n");
fprintf (stderr,
"mongodb://user:pass@localhost:27017\t"
"local machine on port 27017, and authenticate with username "
"user and password pass\n");
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]);
}
other_host_and_port = argc > 2 ? argv[2] : NULL;
client = mongoc_client_new (host_and_port);
if (!client) {
fprintf (stderr, "Invalid hostname or port: %s\n", 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\n");
if (!insert_data (collection)) {
res = 3;
goto cleanup;
}
printf ("explain\n");
if (!explain (collection)) {
res = 4;
goto cleanup;
}
if (other_host_and_port) {
printf ("copydb\n");
if (!copydb (client, other_host_and_port)) {
res = 5;
goto cleanup;
}
printf ("clone collection\n");
if (!clone_collection (database, other_host_and_port)) {
res = 6;
goto cleanup;
}
}
cleanup:
if (collection) {
mongoc_collection_destroy (collection);
}
if (database) {
mongoc_database_destroy (database);
}
if (client) {
mongoc_client_destroy (client);
}
bson_free (host_and_port);
mongoc_cleanup ();
return res;
}
First launch two separate instances of mongod (must be done from separate shells):
$ mongod
$ mkdir /tmp/db2$ mongod --dbpath /tmp/db2 --port 27018 # second instance
Now compile and run the example program:
$ cd examples/common_operations/$ gcc -Wall -o example common-operations.c $(pkg-config --cflags --libs libmongoc-1.0)$ ./example localhost:27017 localhost:27018
Inserting data
explain
{
"executionStats" : {
"allPlansExecution" : [],
"executionStages" : {
"advanced" : 19,
"direction" : "forward" ,
"docsExamined" : 76,
"executionTimeMillisEstimate" : 0,
"filter" : {
"x" : {
"$eq" : 1
}
},
"invalidates" : 0,
"isEOF" : 1,
"nReturned" : 19,
"needTime" : 58,
"needYield" : 0,
"restoreState" : 0,
"saveState" : 0,
"stage" : "COLLSCAN" ,
"works" : 78
},
"executionSuccess" : true,
"executionTimeMillis" : 0,
"nReturned" : 19,
"totalDocsExamined" : 76,
"totalKeysExamined" : 0
},
"ok" : 1,
"queryPlanner" : {
"indexFilterSet" : false,
"namespace" : "test.things",
"parsedQuery" : {
"x" : {
"$eq" : 1
}
},
"plannerVersion" : 1,
"rejectedPlans" : [],
"winningPlan" : {
"direction" : "forward" ,
"filter" : {
"x" : {
"$eq" : 1
}
},
"stage" : "COLLSCAN"
}
},
"serverInfo" : {
"gitVersion" : "05552b562c7a0b3143a729aaa0838e558dc49b25" ,
"host" : "MacBook-Pro-57.local",
"port" : 27017,
"version" : "3.2.6"
}
}
copydb
{ "ok" : 1 }
clone collection
{ "ok" : 1 }