├── mongoq.def ├── examples ├── comments_client.q ├── COMMENTS.md └── comments_load.q ├── LICENSE ├── mongo.q ├── mongoc.h ├── README.md ├── k.h └── mongoq.c /mongoq.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | mongo_init 3 | mongo_bulkinsert 4 | mongo_find 5 | mongo_delete 6 | mongo_drop 7 | mongo_cleanup 8 | mongo_add_index -------------------------------------------------------------------------------- /examples/comments_client.q: -------------------------------------------------------------------------------- 1 | 2 | \l mongo.q 3 | 4 | .mg.initdb`kdb; 5 | 6 | \l mydb 7 | 8 | topics:{[term] 10 sublist select score, subreddit, title:60 sublist' link_title from `score xdesc 0!select max score, first subreddit by link_title from .mg.search[`comments;term]} 9 | 10 | threads:{[term] 11 | t:comments comments[`mgid] bin m:.mg.searchid[`comments;term]; 12 | t:(`$.mg.find[`comments;m;`subreddit]),'t; 13 | r:`threads xdesc select threads:count distinct link_id, comments:count i by subreddit from t; 14 | r} 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 AquaQ Analytics 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/COMMENTS.md: -------------------------------------------------------------------------------- 1 | # Comments Database 2 | 3 | The following example demonstrates the use of the mongoq library to act as a document store backing to kdb+ 4 | Internet forum comments are loaded in from a text file, and saved to a kdb+ database. The text fields are stored in MongoDB, with the MongoDB id field maintained in the kdb+ table. 5 | 6 | There are two components to the example - a loader script and a client script with example queries 7 | For the dataset we sourced about 1Gb (uncompressed) of reddit posts, thanks to reddit user [twentythree-nineteen in this thread](http://www.reddit.com/r/datasets/comments/26ijdl/15_million_reddit_comments_from_november_sql_and/) 8 | Dropbox link to zip file [here](https://www.dropbox.com/s/v1wthwif6m3tf3h/comments.sql.zip) 9 | 10 | ## Loader 11 | 12 | This sort of data is relatively hard to parse because of the mess of delimiters contained within the comment fields. I picked the sql file to process as it is easier to identify genuine breaks between records rather than newlines embedded in the comments. 13 | 14 | ## Client script 15 | 16 | The client script loads and initiallises the mongoq library, then loads the comments database which was saved by the loader. Some sample queries are then printed to screen. 17 | -------------------------------------------------------------------------------- /mongo.q: -------------------------------------------------------------------------------- 1 | 2 | \d .mg 3 | 4 | lib:` sv hsym[`$getenv`QHOME],.z.o,`mongoq; 5 | 6 | initc:lib 2: (`mongo_init;3); 7 | insertc:lib 2: (`mongo_bulkinsert;2); 8 | selectc:lib 2: (`mongo_find;3); 9 | deletec:lib 2: (`mongo_delete;2); 10 | dropc:lib 2: (`mongo_drop;1); 11 | cleanupc:lib 2: (`mongo_cleanup;1); 12 | addindex:lib 2: (`mongo_add_index;2); 13 | 14 | e:enlist; 15 | IN:`$"$in"; 16 | ID:`$"_id"; 17 | OID:`$"$oid"; 18 | TEXT:`$"$text"; 19 | SEARCH:`$"$search"; 20 | QUERY:`$"$query"; 21 | ORDERBY:`$"$orderby"; 22 | META:`$"$meta"; 23 | 24 | oidenc:{-9!0x01000000,reverse[0x0 vs `int$14+16*count x],0x0200,reverse[0x0 vs `int$count x],raze 0x00000000,/:raze each "X"$0N 2#/:x} 25 | oiddec:{raze each string 4_'0N 16#14_-8!x} 26 | 27 | oidin:{e[ID]!e e[IN]!e (e OID)!/:e each x} 28 | 29 | proj:{.j.j except[(),x;`]!count[x]#1b} 30 | 31 | add:{[t;x]oidenc insertc[t;.j.j each $[99=p:type x;enlist x;p in 10 98h;x;'`type]]}; 32 | find:{[t;q;c] 33 | jq:.j.j oidin o:oiddec $[0 23 | 24 | #define MONGOC_INSIDE 25 | #include "mongoc-bulk-operation.h" 26 | #include "mongoc-client.h" 27 | #include "mongoc-client-pool.h" 28 | #include "mongoc-collection.h" 29 | #include "mongoc-config.h" 30 | #include "mongoc-cursor.h" 31 | #include "mongoc-database.h" 32 | #include "mongoc-index.h" 33 | #include "mongoc-error.h" 34 | #include "mongoc-flags.h" 35 | #include "mongoc-gridfs.h" 36 | #include "mongoc-gridfs-file.h" 37 | #include "mongoc-gridfs-file-list.h" 38 | #include "mongoc-gridfs-file-page.h" 39 | #include "mongoc-host-list.h" 40 | #include "mongoc-init.h" 41 | #include "mongoc-matcher.h" 42 | #include "mongoc-opcode.h" 43 | #include "mongoc-log.h" 44 | #include "mongoc-socket.h" 45 | #include "mongoc-stream.h" 46 | #include "mongoc-stream-buffered.h" 47 | #include "mongoc-stream-file.h" 48 | #include "mongoc-stream-gridfs.h" 49 | #include "mongoc-stream-socket.h" 50 | #include "mongoc-uri.h" 51 | #include "mongoc-write-concern.h" 52 | #include "mongoc-version.h" 53 | #ifdef MONGOC_ENABLE_SSL 54 | #include "mongoc-rand.h" 55 | #include "mongoc-stream-tls.h" 56 | #include "mongoc-ssl.h" 57 | #endif 58 | #undef MONGOC_INSIDE 59 | 60 | 61 | #endif /* MONGOC_H */ 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mongoq 2 | 3 | ## About 4 | A C shared lib along with associated q functions to allow push/pull access to mongoDB from within kdb+ 5 | 6 | ## Installation 7 | 8 | - Install the mongo c driver libraries | [repo](https://github.com/mongodb/mongo-c-driver) | [instructions](https://github.com/mongodb/mongo-c-driver/blob/master/TUTORIAL.md) 9 | - Clone the mongoq git repo 10 | - Compile shared object using platform specific instructions below 11 | 12 | ###### Linux (64 bit) 13 | ``` 14 | gcc -o mongoq.so mongoq.c $(pkg-config --cflags --libs libmongoc-1.0) -I./ -shared -fPIC 15 | ``` 16 | ###### Windows 17 | ``` 18 | CL /DWIN32 /I C:\usr\include\libbson-1.0 /I C:\usr\include\libmongoc-1.0 /LIBPATH C:\usr\lib\bson-1.0.lib /LIBPATH C:\usr\lib\mongoc-1.0.lib /LD mongoq.c q.lib /DEF mongoq.def 19 | ``` 20 | 21 | - copy the shared library file from the bin folder to the location of your q executable - e.g. $QHOME/l32 22 | - copy mongo.q to $QHOME 23 | 24 | ## Usage 25 | 26 | #### Load and initialise library 27 | 28 | This assumes there is a MongoDB server running on the local machine on the standard port - amend the connection details as required for your MongoDB setup 29 | ``` 30 | \l mongo.q 31 | .mg.init[`localhost;27017;`kdb] 32 | ``` 33 | 34 | #### Insert data to MongoDB 35 | 36 | ``` 37 | q).mg.add[`test] `a`b`c!(1;`xyz;12t) / single record 38 | 00000000-54ef-b9bd-dfa8-32369e099741 39 | q)r:.mg.add[`test] ([]time:3 4t;sym:`IBM`MSFT;price:23.4 56.7) / table 40 | ``` 41 | 42 | #### Query data from MongoDB 43 | 44 | The '.mg.add' function returns a 16 byte UID type, which maps to the MongoDB ObjectID key of the inserted record. We can use these ids to retrieve data: 45 | ``` 46 | q).mg.find[`test;;()] r / all fields for id(s) r in table 'test' 47 | time sym price 48 | --------------------------- 49 | "03:00:00.000" "IBM" 23.4 50 | "04:00:00.000" "MSFT" 56.7 51 | q).mg.find[`test;;`sym`price] r / only sym & price fields 52 | sym price 53 | ------------ 54 | "IBM" 23.4 55 | "MSFT" 56.7 56 | ``` 57 | 58 | ## Examples 59 | 60 | - [Comments database](examples/COMMENTS.md) 61 | 62 | -------------------------------------------------------------------------------- /examples/comments_load.q: -------------------------------------------------------------------------------- 1 | if[not 2<=count .z.x;-1"Usage q comments_load.q DB FILE";exit 1] 2 | 3 | db:hsym`$.z.x 0; 4 | file:hsym`$.z.x 1; 5 | 6 | \l mongo.q 7 | 8 | c:`subreddit_id`link_title`banned_by`subreddit`likes`replies`id`gilded`author`parent_id`approved_by`body`edited`author_flair_css_class`downs`body_html`link_id`score_hidden`name`created`created_datetime`author_flair_text`created_utc`ups`num_reports`distinguished`word_count`word_length`kincaid!"SSISIISISSI*BSI*SBSSPSSIIIIFF"; 9 | 10 | 11 | inquotes:{mod[sums (x="\"") and not["\\"=prev x] and not["\\"=prev prev x];2]} 12 | niq:{not mod[sums (x="'") and not ("'"=prev x) or "'"=next x;2]} 13 | 14 | pf:"SI*BPF"!({`$1_'-1_'trim x};"I"$;{1_'-1_'trim x};"B"$;"P"$;"F"$); 15 | 16 | td:(`symbol$())!`timespan$(); 17 | 18 | parsedata:{[f;i;l] 19 | -1"Processing - ",(neg[count string fs]$string floor i%1024*1024)," of ",string[fs:`int$hcount[f]%1024*1024]," MB : ",string[.1*`int$1000*i%hcount f],"%"; 20 | st:.z.p; 21 | x:`char$read1(f;i;l); 22 | td[`reading]+:(st:.z.p)-st; 23 | sor:ss[x;"\n('"]; 24 | eor:ss[x;"),\n"]; 25 | x:@[x;;:;" "] where (x in "\":\\{}[];") or x<32; 26 | d:min each sor group eor eor binr sor; 27 | lines:(2+value d)_ x; 28 | lines:",",'(0^-2+key[d]-value d)#'lines; 29 | delims:where each (","=lines)and niq each lines; 30 | linesok:where count[c]=count each delims; 31 | t:key[c]!flip 1_''delims[linesok] _' lines[linesok]; 32 | t:flip pf[c]@'t; 33 | td[`parsing]+:(st:.z.p)-st; 34 | if[count t;processdata[t]]; 35 | i+0^key[d] last linesok}; 36 | 37 | processdata:{[t] 38 | mgcols:`link_title`subreddit`body`body_html`author_flair_text; 39 | st:.z.p; 40 | oid:.mg.add[`comments;mgcols#t]; 41 | td[`mongoinsert]+:(st:.z.p)-st; 42 | (` sv db,`comments`) upsert .Q.en[db] (mgcols _ t),'([]mgid:oid); 43 | td[`kdbwrite]+:(st:.z.p)-st; 44 | }; 45 | 46 | / initialise mongo client 47 | .mg.initdb[`kdb]; 48 | / clear any mongo data from previous loads 49 | .mg.dropc[`comments]; 50 | / similarly, blow away any kdb data from last load 51 | system"rm -rf ",1 _ string db; 52 | / parse file in 10Mb chunks 53 | parsedata[file;;10000000]/[0]; 54 | st:.z.p; 55 | / generate text index on body field 56 | .mg.addindex[`comments;.j.j enlist[`body]!enlist `text] 57 | td[`mongoindex]+:.z.p-st; 58 | td[`TOTAL]:sum td; 59 | 60 | / Print timing results 61 | -1@'{h,x,h:enlist " #"l=l:x 0}"# ",/:(` vs .Q.s td),\:" #"; 62 | exit 0; 63 | -------------------------------------------------------------------------------- /k.h: -------------------------------------------------------------------------------- 1 | #ifndef KX 2 | #define KX 3 | typedef char*S,C;typedef unsigned char G;typedef short H;typedef int I;typedef long long J;typedef float E;typedef double F;typedef void V; 4 | #ifdef __cplusplus 5 | extern"C"{ 6 | #endif 7 | #ifndef KXVER 8 | #error "Set KXVER=3 for kdb+3.0 or standalone c-api after 2011-04-20. Otherwise set KXVER=2" 9 | #endif 10 | #if KXVER>=3 11 | typedef struct k0{signed char m,a,t;C u;I r;union{G g;H h;I i;J j;E e;F f;S s;struct k0*k;struct{J n;G G0[1];};};}*K; 12 | typedef struct{G g[16];}U; 13 | #define kU(x) ((U*)kG(x)) 14 | #define xU ((U*)xG) 15 | extern K ku(U),ktn(I,J),kpn(S,J); 16 | extern I setm(I); 17 | #define DO(n,x) {J i=0,_i=(n);for(;i<_i;++i){x;}} 18 | #else 19 | typedef struct k0{I r;H t,u;union{G g;H h;I i;J j;E e;F f;S s;struct k0*k;struct{I n;G G0[1];};};}*K; 20 | extern K ktn(I,I),kpn(S,I); 21 | #define DO(n,x) {I i=0,_i=(n);for(;i<_i;++i){x;}} 22 | #endif 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | //#include 27 | // vector accessors, e.g. kF(x)[i] for float&datetime 28 | #define kG(x) ((x)->G0) 29 | #define kC(x) kG(x) 30 | #define kH(x) ((H*)kG(x)) 31 | #define kI(x) ((I*)kG(x)) 32 | #define kJ(x) ((J*)kG(x)) 33 | #define kE(x) ((E*)kG(x)) 34 | #define kF(x) ((F*)kG(x)) 35 | #define kS(x) ((S*)kG(x)) 36 | #define kK(x) ((K*)kG(x)) 37 | 38 | // type bytes qtype ctype accessor 39 | #define KB 1 // 1 boolean char kG 40 | #define UU 2 // 16 guid U kU 41 | #define KG 4 // 1 byte char kG 42 | #define KH 5 // 2 short short kH 43 | #define KI 6 // 4 int int kI 44 | #define KJ 7 // 8 long long kJ 45 | #define KE 8 // 4 real float kE 46 | #define KF 9 // 8 float double kF 47 | #define KC 10 // 1 char char kC 48 | #define KS 11 // * symbol char* kS 49 | 50 | #define KP 12 // 8 timestamp long kJ (nanoseconds from 2000.01.01) 51 | #define KM 13 // 4 month int kI (months from 2000.01.01) 52 | #define KD 14 // 4 date int kI (days from 2000.01.01) 53 | 54 | #define KN 16 // 8 timespan long kJ (nanoseconds) 55 | #define KU 17 // 4 minute int kI 56 | #define KV 18 // 4 second int kI 57 | #define KT 19 // 4 time int kI (millisecond) 58 | 59 | #define KZ 15 // 8 datetime double kF (DO NOT USE) 60 | 61 | // table,dict 62 | #define XT 98 // x->k is XD 63 | #define XD 99 // kK(x)[0] is keys. kK(x)[1] is values. 64 | 65 | #ifdef __cplusplus 66 | extern"C"{ 67 | extern V m9(); 68 | #else 69 | extern V m9(V); 70 | #endif 71 | extern I khpun(const S,I,const S,I),khpu(const S,I,const S),khp(const S,I),okx(K),ymd(I,I,I),dj(I);extern V r0(K),sd0(I),kclose(I);extern S sn(S,I),ss(S); 72 | extern K ktj(I,J),ka(I),kb(I),kg(I),kh(I),ki(I),kj(J),ke(F),kf(F),kc(I),ks(S),kd(I),kz(F),kt(I),sd1(I,K(*)(I)),dl(V*f,I), 73 | knk(I,...),kp(S),ja(K*,V*),js(K*,S),jk(K*,K),jv(K*k,K),k(I,const S,...),xT(K),xD(K,K),ktd(K),r1(K),krr(const S),orr(const S),dot(K,K),b9(I,K),d9(K); 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | 78 | // nulls(n?) and infinities(w?) 79 | #define nh ((I)0xFFFF8000) 80 | #define wh ((I)0x7FFF) 81 | #define ni ((I)0x80000000) 82 | #define wi ((I)0x7FFFFFFF) 83 | #define nj ((J)0x8000000000000000LL) 84 | #define wj 0x7FFFFFFFFFFFFFFFLL 85 | #if WIN32 || _WIN32 86 | #define nf (log(-1.0)) 87 | #define wf (-log(0.0)) 88 | #define isnan _isnan 89 | #define finite _finite 90 | extern double log(double); 91 | #else 92 | #define nf (0/0.0) 93 | #define wf (1/0.0) 94 | #define closesocket(x) close(x) 95 | #endif 96 | 97 | // remove more clutter 98 | #define O printf 99 | #define R return 100 | #define Z static 101 | #define P(x,y) {if(x)R(y);} 102 | #define U(x) P(!(x),0) 103 | #define SW switch 104 | #define CS(n,x) case n:x;break; 105 | #define CD default 106 | 107 | #define ZV Z V 108 | #define ZK Z K 109 | #define ZH Z H 110 | #define ZI Z I 111 | #define ZJ Z J 112 | #define ZE Z E 113 | #define ZF Z F 114 | #define ZC Z C 115 | #define ZS Z S 116 | 117 | #define K1(f) K f(K x) 118 | #define K2(f) K f(K x,K y) 119 | #define TX(T,x) (*(T*)((G*)(x)+8)) 120 | #define xr x->r 121 | #define xt x->t 122 | #define xu x->u 123 | #define xn x->n 124 | #define xx xK[0] 125 | #define xy xK[1] 126 | #define xg TX(G,x) 127 | #define xh TX(H,x) 128 | #define xi TX(I,x) 129 | #define xj TX(J,x) 130 | #define xe TX(E,x) 131 | #define xf TX(F,x) 132 | #define xs TX(S,x) 133 | #define xk TX(K,x) 134 | #define xG x->G0 135 | #define xH ((H*)xG) 136 | #define xI ((I*)xG) 137 | #define xJ ((J*)xG) 138 | #define xE ((E*)xG) 139 | #define xF ((F*)xG) 140 | #define xS ((S*)xG) 141 | #define xK ((K*)xG) 142 | #define xC xG 143 | #define xB ((G*)xG) 144 | 145 | #endif 146 | 147 | -------------------------------------------------------------------------------- /mongoq.c: -------------------------------------------------------------------------------- 1 | #define KXVER 3 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include"k.h" 8 | 9 | bool initialised = false; 10 | mongoc_client_t *client; 11 | char *database; 12 | 13 | K mongo_init(K qhost, K qport, K qdatabase) 14 | { 15 | char *host; 16 | int port; 17 | host = qhost->s; 18 | port = qport->i; 19 | database = qdatabase->s; 20 | char *uri; 21 | 22 | mongoc_init (); 23 | 24 | uri = bson_strdup_printf ("mongodb://%s:%d/%s?ssl=%s", 25 | host, 26 | port, 27 | database, 28 | "false"); 29 | 30 | if (!(client = mongoc_client_new (uri))) { 31 | mongoc_cleanup (); 32 | krr("Invalid connection details"); 33 | return (K)0; 34 | } 35 | initialised = true; 36 | return (K)0; 37 | } 38 | 39 | K mongo_cleanup(K x) 40 | { 41 | mongoc_client_destroy (client); 42 | mongoc_cleanup (); 43 | initialised = false; 44 | return (K)0; 45 | } 46 | 47 | K mongo_delete(K qtable, K qquery) 48 | { 49 | mongoc_collection_t *collection; 50 | bson_error_t error; 51 | bson_t *doc; 52 | collection = mongoc_client_get_collection (client, database, qtable->s); 53 | doc = bson_new_from_json(kC(qquery),qquery->n,&error); 54 | mongoc_collection_remove (collection, MONGOC_REMOVE_NONE, doc, NULL, &error); 55 | bson_destroy(doc); 56 | mongoc_collection_destroy (collection); 57 | return (K)0; 58 | } 59 | 60 | K mongo_drop(K qtable) 61 | { 62 | mongoc_collection_t *collection; 63 | bson_error_t error; 64 | collection = mongoc_client_get_collection (client, database, qtable->s); 65 | mongoc_collection_drop (collection, &error); 66 | mongoc_collection_destroy (collection); 67 | return (K)0; 68 | } 69 | 70 | K mongo_add_index(K qtable, K qquery) 71 | { 72 | mongoc_collection_t *collection; 73 | bson_error_t error; 74 | bson_t *doc; 75 | collection = mongoc_client_get_collection (client, database, qtable->s); 76 | doc = bson_new_from_json(kC(qquery),qquery->n,&error); 77 | mongoc_collection_create_index (collection, doc, NULL, &error); 78 | bson_destroy(doc); 79 | mongoc_collection_destroy (collection); 80 | return (K)0; 81 | } 82 | 83 | 84 | K mongo_bulkinsert(K table, K records) 85 | { 86 | mongoc_collection_t *collection; 87 | mongoc_bulk_operation_t *bulk; 88 | bson_error_t error; 89 | bson_t *doc; 90 | bson_oid_t oid; 91 | bson_t reply; 92 | char *str; 93 | bool ret; 94 | int i; 95 | char oidstr[25]; 96 | K qoids,qoid; 97 | 98 | collection = mongoc_client_get_collection (client, database, table->s); 99 | bulk = mongoc_collection_create_bulk_operation (collection, true, NULL); 100 | qoids = ktn(0, records->n); 101 | 102 | for (i = 0; i < records->n; i++) { 103 | bson_oid_init (&oid, NULL); 104 | doc = bson_new_from_json(kC(kK(records)[i]),(kK(records)[i])->n,&error); 105 | bson_append_oid(doc, "_id", -1, &oid); 106 | mongoc_bulk_operation_insert (bulk, doc); 107 | bson_destroy (doc); 108 | bson_oid_to_string(&oid, oidstr); 109 | kK(qoids)[i] = kp(oidstr); 110 | } 111 | 112 | ret = mongoc_bulk_operation_execute (bulk, &reply, &error); 113 | 114 | if (!ret) { 115 | krr(error.message); 116 | return (K)0; 117 | } 118 | 119 | bson_destroy (&reply); 120 | mongoc_bulk_operation_destroy (bulk); 121 | mongoc_collection_destroy (collection); 122 | 123 | return qoids; 124 | } 125 | 126 | 127 | K mongo_find(K qtable, K qquery, K qfields) 128 | { 129 | // mongoc_client_t *client; 130 | mongoc_collection_t *collection; 131 | mongoc_cursor_t *cursor; 132 | const bson_t *item; 133 | bson_error_t error; 134 | bson_t *query; 135 | bson_t *fields; 136 | char *str; 137 | bool r; 138 | char oidstr[25]; 139 | int i; 140 | K rtn,record; 141 | 142 | if(qquery->t!=10){krr("type");return (K)0;}; 143 | 144 | /* get a handle to our collection */ 145 | collection = mongoc_client_get_collection (client, database, qtable->s); 146 | 147 | query = bson_new_from_json(kC(qquery),qquery->n,&error); 148 | fields = bson_new_from_json(kC(qfields),qfields->n,&error); 149 | 150 | /* execute the query and iterate the results */ 151 | cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0, query, fields, NULL); 152 | rtn = ktn(0, 0); 153 | while (mongoc_cursor_next (cursor, &item)) { 154 | str = bson_as_json (item, NULL); 155 | record = kp(str); 156 | jk(&rtn,record); 157 | bson_free (str); 158 | } 159 | if (mongoc_cursor_error (cursor, &error)) { 160 | krr(error.message); 161 | return(K)0; 162 | } 163 | 164 | 165 | /* release everything */ 166 | mongoc_cursor_destroy (cursor); 167 | mongoc_collection_destroy (collection); 168 | // mongoc_client_destroy (client); 169 | bson_destroy (query); 170 | bson_destroy (fields); 171 | 172 | return rtn; 173 | } 174 | 175 | --------------------------------------------------------------------------------