Docs Menu
Docs Home
/ / /
C 드라이버
/ /

"distinct" 및 "mapReduce"

이 페이지의 내용

  • 설정
  • "distinct" 명령
  • "mapReduce" - 기본 예제
  • "mapReduce" - 더 복잡한 예제
  • 예제 실행

이 문서에서는 distinctmapReduce 명령을 보여주는 몇 가지 실용적이고 간단한 예제를 제공합니다.

먼저 샘플 데이터를 삽입하는 코드를 쓰기 (write) 보겠습니다.

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 ("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)
{
char *str;
BSON_ASSERT (reply);
str = bson_as_canonical_extended_json (reply, NULL);
printf ("%s\n", str);
bson_free (str);
}

다음은 distinct 명령을 사용하여 1 보다 큰 x 의 고유 값을 가져오는 방법입니다.

distinct.c
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\n", 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 \"values\" field from response\n");
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\n", val);
}
}
cleanup:
/* cleanup */
bson_destroy (command);
bson_destroy (&reply);
return res;
}

맵 리듀스 프레임워크를 사용한 간단한 예제입니다. 각 "태그"의 발생 횟수를 합산할 뿐입니다.

먼저 mapreduce 함수를 정의합니다.

상수.c
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. */

mapReduce 명령을 실행합니다. 일반 명령 헬퍼를 사용합니다(예: mongoc_database_command_simple). 읽기 명령 헬퍼(예: mongoc_database_read_command_with_opts) 재시도 가능한 읽기 작업으로 간주되기 때문입니다. 재시도 가능 읽기가 활성화되면 해당 작업은 재시도 가능 오류가 발생할 때 한 번 재시도하여 mapReduce 에 바람직하지 않은 동작을 발생시킵니다.

map-reduce-basic.c
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 = "outCollection";
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 "query" or
"limit" and so on */
bson_t *const 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);
if (!res) {
fprintf (stderr, "MapReduce failed: %s\n", 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 */
const bson_t *doc = NULL;
while (mongoc_cursor_next (cursor, &doc)) {
print_res (doc);
}
if (mongoc_cursor_error (cursor, &error)) {
fprintf (stderr, "ERROR: %s\n", 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;
}

이를 위해서는 복제본 세트 실행 어야 합니다.

이 예시 에서는 복제본 세트 의 세컨더리 에 문의 하여 '인라인' 맵 리듀스를 수행하여 결과가 즉시 반환되도록 합니다.

map-reduce-advanced.c
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\n", error.message);
res = false;
}
mongoc_cursor_destroy (cursor);
mongoc_read_prefs_destroy (read_pref);
bson_destroy (command);
return res;
}

예시 코드를 실행 하는 방법은 다음과 같습니다.

Basic-aggregation.c
/*
* Copyright 2009-present 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/mongoc.h>
#include <stdio.h>
#include "constants.c"
#include "../doc-common-insert.c"
#include "distinct.c"
#include "map-reduce-basic.c"
#include "map-reduce-advanced.c"
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, "usage: %s CONNECTION-STRING\n", argv[0]);
fprintf (stderr, "the 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 exit_code;
}
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]);
}
uri = mongoc_uri_new_with_error (host_and_port, &error);
if (!uri) {
fprintf (stderr,
"failed to parse URI: %s\n"
"error message: %s\n",
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, "test");
collection = mongoc_database_get_collection (database, COLLECTION_NAME);
printf ("Inserting data\n");
if (!insert_data (collection)) {
goto cleanup;
}
printf ("distinct\n");
if (!distinct (database)) {
goto cleanup;
}
printf ("map reduce\n");
if (!map_reduce_basic (database)) {
goto cleanup;
}
printf ("more complicated map reduce\n");
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;
}

세컨더리 를 사용하여 고급 맵 리듀스 예시 를 시도하려면 복제본 세트 를 시작하세요(이 작업을 수행하는 방법에 대한 지침은 여기).

그렇지 않으면 MongoDB 인스턴스를 시작하기만 하면 됩니다.

$ mongod

이제 예제 프로그램을 컴파일하고 실행합니다.

$ 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
{ "result" : "outCollection", "timeMillis" : 155, "counts" : { "input" : 84, "emit" : 126, "reduce" : 3, "output" : 3 }, "ok" : 1 }
{ "_id" : "cat", "value" : 63 }
{ "_id" : "dog", "value" : 42 }
{ "_id" : "mouse", "value" : 21 }
more complicated map reduce
{ "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 }

돌아가기

애그리게이션 프레임워크 예제