From 25141680e2ff3a26908f559338625192550f621c Mon Sep 17 00:00:00 2001 From: fbraem Date: Tue, 19 Feb 2013 22:59:47 +0100 Subject: [PATCH 01/13] Add first samples --- MongoDB/samples/SQLToMongo/src/main.cpp | 123 ++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 MongoDB/samples/SQLToMongo/src/main.cpp diff --git a/MongoDB/samples/SQLToMongo/src/main.cpp b/MongoDB/samples/SQLToMongo/src/main.cpp new file mode 100644 index 000000000..3de49c7a2 --- /dev/null +++ b/MongoDB/samples/SQLToMongo/src/main.cpp @@ -0,0 +1,123 @@ +// +// main.cpp +// +// $Id$ +// +// This sample shows SQL to mongo Shell to C++ examples. +// +// Copyright (c) 2013, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/MongoDB/MongoDB.h" +#include "Poco/MongoDB/Connection.h" +#include "Poco/MongoDB/Database.h" +#include "Poco/MongoDB/Cursor.h" + +// INSERT INTO USERS +// VALUES( "Braem", 33) +void sample1(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 1 ***" << std::endl; + + Poco::MongoDB::Database db("mydb"); + + Poco::SharedPtr insertUserRequest = db.createInsertRequest("users"); + Poco::MongoDB::Document::Ptr user = new Poco::MongoDB::Document(); + user->add("lastname", std::string("Braem")); + user->add("age", 33); + insertUserRequest->documents().push_back(user); + connection.sendRequest(*insertUserRequest); + std::string lastError = db.getLastError(connection); + if ( !lastError.empty() ) + { + std::cout << "Last Error: " << db.getLastError(connection) << std::endl; + } +} + +// SELECT lastname, age FROM users +void sample2(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 2 ***" << std::endl; + + Poco::MongoDB::Cursor cursor("mydb", "users"); + // Selecting fields is done by adding them to the returnFieldSelector + // Use 1 as value of the element. + cursor.query().returnFieldSelector().add("lastname", 1); + cursor.query().returnFieldSelector().add("age", 1); + Poco::MongoDB::ResponseMessage& response = cursor.next(connection); + while(1) + { + for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) + { + std::cout << "LastName: " << (*it)->get("lastname") << " Age: " << (*it)->get("age") << std::endl; + } + + // When the cursorID is 0, there are no documents left, so break out ... + if ( response.cursorID() == 0 ) + { + break; + } + + // Get the next bunch of documents + response = cursor.next(connection); + } +} + +// SELECT * FROM users +void sample3(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 3 ***" << std::endl; + + Poco::MongoDB::Cursor cursor("mydb", "users"); + Poco::MongoDB::ResponseMessage& response = cursor.next(connection); + while(1) + { + for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) + { + std::cout << "LastName: " << (*it)->get("lastname") << " Age: " << (*it)->get("age") << std::endl; + } + + // When the cursorID is 0, there are no documents left, so break out ... + if ( response.cursorID() == 0 ) + { + break; + } + + // Get the next bunch of documents + response = cursor.next(connection); + }; +} + +int main(int argc, char** argv) +{ + Poco::MongoDB::Connection connection("localhost", 27017); + sample1(connection); + sample2(connection); + sample3(connection); + + return 0; +} From e04dca0e130d0ad9d435024fca880649b50c5f60 Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 20 Feb 2013 22:20:29 +0100 Subject: [PATCH 02/13] Provide an add method for a char* value --- MongoDB/include/Poco/MongoDB/Document.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MongoDB/include/Poco/MongoDB/Document.h b/MongoDB/include/Poco/MongoDB/Document.h index 436428a3f..eeb1f233f 100644 --- a/MongoDB/include/Poco/MongoDB/Document.h +++ b/MongoDB/include/Poco/MongoDB/Document.h @@ -99,6 +99,14 @@ public: } + void add(const std::string& name, const char* value) + /// Creates an element with the given name and value + // adds it to the document. + { + addElement(new ConcreteElement(name, std::string(value))); + } + + void clear(); /// Removes all elements from the document. From e79f75d9fe93242b8de93194dbc4d60d6af2903b Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 20 Feb 2013 22:20:55 +0100 Subject: [PATCH 03/13] Rename query() method to selector() --- MongoDB/include/Poco/MongoDB/QueryRequest.h | 12 ++++++------ MongoDB/src/Database.cpp | 4 ++-- MongoDB/src/QueryRequest.cpp | 4 ++-- MongoDB/src/ReplicaSet.cpp | 2 +- MongoDB/testsuite/src/MongoDBTest.cpp | 12 ++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/MongoDB/include/Poco/MongoDB/QueryRequest.h b/MongoDB/include/Poco/MongoDB/QueryRequest.h index f953e6117..001393571 100644 --- a/MongoDB/include/Poco/MongoDB/QueryRequest.h +++ b/MongoDB/include/Poco/MongoDB/QueryRequest.h @@ -105,12 +105,12 @@ public: /// Sets the number to return (limit) - Document& query(); - /// Returns the query document + Document& selector(); + /// Returns the selector document Document& returnFieldSelector(); - /// Returns the selector document + /// Returns the field selector document protected: @@ -128,7 +128,7 @@ private: Int32 _numberToReturn; - Document _query; + Document _selector; Document _returnFieldSelector; }; @@ -152,9 +152,9 @@ inline std::string QueryRequest::fullCollectionName() const } -inline Document& QueryRequest::query() +inline Document& QueryRequest::selector() { - return _query; + return _selector; } diff --git a/MongoDB/src/Database.cpp b/MongoDB/src/Database.cpp index e5be810f6..d34246851 100644 --- a/MongoDB/src/Database.cpp +++ b/MongoDB/src/Database.cpp @@ -75,7 +75,7 @@ Document::Ptr Database::getLastErrorDoc(Connection& connection) const Poco::SharedPtr request = createQueryRequest("$cmd"); request->setNumberToReturn(1); - request->query().add("getLastError", 1); + request->selector().add("getLastError", 1); Poco::MongoDB::ResponseMessage response; connection.sendRequest(*request, response); @@ -110,7 +110,7 @@ Poco::SharedPtr Database::createCountRequest(const { Poco::SharedPtr request = createQueryRequest("$cmd"); request->setNumberToReturn(1); - request->query().add("count", collectionName); + request->selector().add("count", collectionName); return request; } diff --git a/MongoDB/src/QueryRequest.cpp b/MongoDB/src/QueryRequest.cpp index 270075abe..6fb32bf46 100644 --- a/MongoDB/src/QueryRequest.cpp +++ b/MongoDB/src/QueryRequest.cpp @@ -49,7 +49,7 @@ QueryRequest::QueryRequest(const std::string& collectionName, QueryRequest::Flag _fullCollectionName(collectionName), _numberToSkip(0), _numberToReturn(100), - _query(), + _selector(), _returnFieldSelector() { } @@ -65,7 +65,7 @@ void QueryRequest::buildRequest(BinaryWriter& writer) BSONWriter(writer).writeCString(_fullCollectionName); writer << _numberToSkip; writer << _numberToReturn; - _query.write(writer); + _selector.write(writer); if ( ! _returnFieldSelector.empty() ) { diff --git a/MongoDB/src/ReplicaSet.cpp b/MongoDB/src/ReplicaSet.cpp index be26aa79b..6919a3faa 100644 --- a/MongoDB/src/ReplicaSet.cpp +++ b/MongoDB/src/ReplicaSet.cpp @@ -78,7 +78,7 @@ Connection::Ptr ReplicaSet::isMaster(const Net::SocketAddress& address) QueryRequest request("admin.$cmd"); request.setNumberToReturn(1); - request.query().add("isMaster", 1); + request.selector().add("isMaster", 1); ResponseMessage response; conn->sendRequest(request, response); diff --git a/MongoDB/testsuite/src/MongoDBTest.cpp b/MongoDB/testsuite/src/MongoDBTest.cpp index 948cbd263..aef99fe09 100644 --- a/MongoDB/testsuite/src/MongoDBTest.cpp +++ b/MongoDB/testsuite/src/MongoDBTest.cpp @@ -124,7 +124,7 @@ void MongoDBTest::testQueryRequest() } Poco::MongoDB::QueryRequest request("team.players"); - request.query().add("lastname" , std::string("Braem")); + request.selector().add("lastname" , std::string("Braem")); request.setNumberToReturn(1); Poco::MongoDB::ResponseMessage response; @@ -173,7 +173,7 @@ void MongoDBTest::testDBQueryRequest() Database db("team"); Poco::SharedPtr request = db.createQueryRequest("players"); - request->query().add("lastname" , std::string("Braem")); + request->selector().add("lastname" , std::string("Braem")); Poco::MongoDB::ResponseMessage response; _mongo.sendRequest(*request, response); @@ -219,7 +219,7 @@ void MongoDBTest::testCountCommand() Poco::MongoDB::QueryRequest request("team.$cmd"); request.setNumberToReturn(1); - request.query().add("count", std::string("players")); + request.selector().add("count", std::string("players")); Poco::MongoDB::ResponseMessage response; @@ -331,7 +331,7 @@ void MongoDBTest::testCursorRequest() Poco::MongoDB::QueryRequest drop("team.$cmd"); drop.setNumberToReturn(1); - drop.query().add("drop", std::string("numbers")); + drop.selector().add("drop", std::string("numbers")); Poco::MongoDB::ResponseMessage responseDrop; _mongo.sendRequest(drop, responseDrop); @@ -353,7 +353,7 @@ void MongoDBTest::testBuildInfo() Poco::MongoDB::QueryRequest request("team.$cmd"); request.setNumberToReturn(1); - request.query().add("buildInfo", 1); + request.selector().add("buildInfo", 1); Poco::MongoDB::ResponseMessage response; @@ -388,7 +388,7 @@ void MongoDBTest::testConnectionPool() Poco::MongoDB::QueryRequest request("team.$cmd"); request.setNumberToReturn(1); - request.query().add("count", std::string("players")); + request.selector().add("count", std::string("players")); Poco::MongoDB::ResponseMessage response; ((Connection::Ptr) pooledConnection)->sendRequest(request, response); From 7600eed5028078e23742e6c4a43bdf54884978f1 Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 20 Feb 2013 22:21:26 +0100 Subject: [PATCH 04/13] Add more samples --- MongoDB/samples/SQLToMongo/src/main.cpp | 152 +++++++++++++++++++++--- 1 file changed, 137 insertions(+), 15 deletions(-) diff --git a/MongoDB/samples/SQLToMongo/src/main.cpp b/MongoDB/samples/SQLToMongo/src/main.cpp index 3de49c7a2..931cf6091 100644 --- a/MongoDB/samples/SQLToMongo/src/main.cpp +++ b/MongoDB/samples/SQLToMongo/src/main.cpp @@ -37,19 +37,41 @@ #include "Poco/MongoDB/Database.h" #include "Poco/MongoDB/Cursor.h" -// INSERT INTO USERS -// VALUES( "Braem", 33) +// INSERT INTO players +// VALUES( "Messi", "Lionel", 1987) void sample1(Poco::MongoDB::Connection& connection) { std::cout << "*** SAMPLE 1 ***" << std::endl; - Poco::MongoDB::Database db("mydb"); + Poco::MongoDB::Database db("sample"); + Poco::SharedPtr insertUserRequest = db.createInsertRequest("players"); + + // With one insert request, we can add multiple documents + + Poco::MongoDB::Document::Ptr player = new Poco::MongoDB::Document(); + player->add("lastname", "Messi"); + player->add("firstname", "Lionel"); + player->add("birthyear", 1987); + insertUserRequest->documents().push_back(player); + + player = new Poco::MongoDB::Document(); + player->add("lastname", "Valdes"); + player->add("firstname", "Victor"); + player->add("birthyear", 1982); + insertUserRequest->documents().push_back(player); + + player = new Poco::MongoDB::Document(); + player->add("lastname", "Puyol"); + player->add("firstname", "Carles"); + player->add("birthyear", 1978); + insertUserRequest->documents().push_back(player); + + player = new Poco::MongoDB::Document(); + player->add("lastname", "Piqué"); + player->add("firstname", "Gerard"); + player->add("birthyear", 1987); + insertUserRequest->documents().push_back(player); - Poco::SharedPtr insertUserRequest = db.createInsertRequest("users"); - Poco::MongoDB::Document::Ptr user = new Poco::MongoDB::Document(); - user->add("lastname", std::string("Braem")); - user->add("age", 33); - insertUserRequest->documents().push_back(user); connection.sendRequest(*insertUserRequest); std::string lastError = db.getLastError(connection); if ( !lastError.empty() ) @@ -58,22 +80,22 @@ void sample1(Poco::MongoDB::Connection& connection) } } -// SELECT lastname, age FROM users +// SELECT lastname, birthyear FROM players void sample2(Poco::MongoDB::Connection& connection) { std::cout << "*** SAMPLE 2 ***" << std::endl; - Poco::MongoDB::Cursor cursor("mydb", "users"); + Poco::MongoDB::Cursor cursor("sample", "players"); // Selecting fields is done by adding them to the returnFieldSelector // Use 1 as value of the element. cursor.query().returnFieldSelector().add("lastname", 1); - cursor.query().returnFieldSelector().add("age", 1); + cursor.query().returnFieldSelector().add("birthyear", 1); Poco::MongoDB::ResponseMessage& response = cursor.next(connection); while(1) { for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) { - std::cout << "LastName: " << (*it)->get("lastname") << " Age: " << (*it)->get("age") << std::endl; + std::cout << (*it)->get("lastname") << " (" << (*it)->get("birthyear") << ')' << std::endl; } // When the cursorID is 0, there are no documents left, so break out ... @@ -87,18 +109,18 @@ void sample2(Poco::MongoDB::Connection& connection) } } -// SELECT * FROM users +// SELECT * FROM players void sample3(Poco::MongoDB::Connection& connection) { std::cout << "*** SAMPLE 3 ***" << std::endl; - Poco::MongoDB::Cursor cursor("mydb", "users"); + Poco::MongoDB::Cursor cursor("sample", "players"); Poco::MongoDB::ResponseMessage& response = cursor.next(connection); while(1) { for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) { - std::cout << "LastName: " << (*it)->get("lastname") << " Age: " << (*it)->get("age") << std::endl; + std::cout << (*it)->get("lastname") << ' ' << (*it)->get("firstname") << " (" << (*it)->get("birthyear") << ')' << std::endl; } // When the cursorID is 0, there are no documents left, so break out ... @@ -112,12 +134,112 @@ void sample3(Poco::MongoDB::Connection& connection) }; } + +// SELECT * FROM players WHERE birthyear = 1978 +void sample4(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 4 ***" << std::endl; + + Poco::MongoDB::Cursor cursor("sample", "players"); + cursor.query().selector().add("birthyear", 1978); + + Poco::MongoDB::ResponseMessage& response = cursor.next(connection); + while(1) + { + for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) + { + std::cout << (*it)->get("lastname") << ' ' << (*it)->get("firstname") << " (" << (*it)->get("birthyear") << ')' << std::endl; + } + + // When the cursorID is 0, there are no documents left, so break out ... + if ( response.cursorID() == 0 ) + { + break; + } + + // Get the next bunch of documents + response = cursor.next(connection); + }; +} + +// SELECT * FROM players WHERE birthyear = 1987 ORDER BY name +void sample5(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 5 ***" << std::endl; + + Poco::MongoDB::Cursor cursor("sample", "players"); + + // When orderby is needed, use 2 separate documents in the query selector + Poco::MongoDB::Document::Ptr query = new Poco::MongoDB::Document(); + query->add("birthyear", 1987); + cursor.query().selector().add("$query", query); + + Poco::MongoDB::Document::Ptr order = new Poco::MongoDB::Document(); + order->add("lastname", 0); + cursor.query().selector().add("$orderby", order); + + Poco::MongoDB::ResponseMessage& response = cursor.next(connection); + while(1) + { + for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) + { + std::cout << (*it)->get("lastname") << ' ' << (*it)->get("firstname") << " (" << (*it)->get("birthyear") << ')' << std::endl; + } + + // When the cursorID is 0, there are no documents left, so break out ... + if ( response.cursorID() == 0 ) + { + break; + } + + // Get the next bunch of documents + response = cursor.next(connection); + }; +} + + +// SELECT * FROM players WHERE birthyear > 1969 and birthyear <= 1980 +void sample6(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 6 ***" << std::endl; + + Poco::MongoDB::Cursor cursor("sample", "players"); + + Poco::MongoDB::Document::Ptr oper = new Poco::MongoDB::Document(); + oper->add("$gt", 1969); + oper->add("$lte", 1980); + + cursor.query().selector().add("birthyear", oper); + + Poco::MongoDB::ResponseMessage& response = cursor.next(connection); + while(1) + { + for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) + { + std::cout << (*it)->get("lastname") << ' ' << (*it)->get("firstname") << " (" << (*it)->get("birthyear") << ')' << std::endl; + } + + // When the cursorID is 0, there are no documents left, so break out ... + if ( response.cursorID() == 0 ) + { + break; + } + + // Get the next bunch of documents + response = cursor.next(connection); + }; +} + + int main(int argc, char** argv) { Poco::MongoDB::Connection connection("localhost", 27017); sample1(connection); sample2(connection); sample3(connection); + sample4(connection); + sample5(connection); + sample6(connection); return 0; } From 7328eace347cf20ad5849de2aac031dfc652f444 Mon Sep 17 00:00:00 2001 From: fbraem Date: Thu, 21 Feb 2013 16:48:21 +0100 Subject: [PATCH 05/13] Add method addNewDocument and return a reference of the active document in the add methods to allow chaining these methods ... --- MongoDB/include/Poco/MongoDB/Document.h | 40 ++++++++++++++++++++----- MongoDB/src/Document.cpp | 4 --- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/MongoDB/include/Poco/MongoDB/Document.h b/MongoDB/include/Poco/MongoDB/Document.h index eeb1f233f..de6884553 100644 --- a/MongoDB/include/Poco/MongoDB/Document.h +++ b/MongoDB/include/Poco/MongoDB/Document.h @@ -86,27 +86,36 @@ public: /// Destructor - void addElement(Element::Ptr element); - /// Add an element to the document + Document& addElement(Element::Ptr element); + /// Add an element to the document. + /// The active document is returned to allow chaining of the add methods. template - void add(const std::string& name, T value) - /// Creates an element with the given name and value + Document& add(const std::string& name, T value) + /// Creates an element with the given name and value and // adds it to the document. + /// The active document is returned to allow chaining of the add methods. { - addElement(new ConcreteElement(name, value)); + return addElement(new ConcreteElement(name, value)); } - void add(const std::string& name, const char* value) - /// Creates an element with the given name and value + Document& add(const std::string& name, const char* value) + /// Creates an element with the given name and value and // adds it to the document. + /// The active document is returned to allow chaining of the add methods. { - addElement(new ConcreteElement(name, std::string(value))); + return addElement(new ConcreteElement(name, std::string(value))); } + Document& addNewDocument(const std::string& name); + /// Create a new document and add it to this document. + /// Unlike the other add methods, this method returns + /// a reference to the new document. + + void clear(); /// Removes all elements from the document. @@ -212,6 +221,21 @@ protected: }; +inline Document& Document::addElement(Element::Ptr element) +{ + _elements.insert(element); + return *this; +} + + +inline Document& Document::addNewDocument(const std::string& name) +{ + Document::Ptr newDoc = new Document(); + add(name, newDoc); + return *newDoc; +} + + inline void Document::clear() { _elements.clear(); diff --git a/MongoDB/src/Document.cpp b/MongoDB/src/Document.cpp index c84a77310..90aa18fbf 100644 --- a/MongoDB/src/Document.cpp +++ b/MongoDB/src/Document.cpp @@ -220,9 +220,5 @@ void Document::write(BinaryWriter& writer) writer << '\0'; } -void Document::addElement(Element::Ptr element) -{ - _elements.insert(element); -} }} // Namespace Poco::MongoDB From 60afc2dbd019f55a1a54d830df260db597bea2c6 Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 22 Feb 2013 19:29:48 +0100 Subject: [PATCH 06/13] Add ensureIndex --- MongoDB/include/Poco/MongoDB/Database.h | 5 ++++ MongoDB/src/Database.cpp | 38 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/MongoDB/include/Poco/MongoDB/Database.h b/MongoDB/include/Poco/MongoDB/Database.h index 9f4a21c5b..7848ae3e9 100644 --- a/MongoDB/include/Poco/MongoDB/Database.h +++ b/MongoDB/include/Poco/MongoDB/Database.h @@ -80,6 +80,11 @@ public: /// The collectionname must not contain the database name! + Poco::MongoDB::Document::Ptr ensureIndex(Connection& connection, const std::string& collection, const std::string& indexName, Poco::MongoDB::Document::Ptr keys, bool unique = false, bool background = false, int version = 0, int ttl = 0); + /// Creates an index. The document returned is the result of a getLastError call. + /// For more info look at the ensureIndex information on the MongoDB website. + + Document::Ptr getLastErrorDoc(Connection& connection) const; /// Sends the getLastError command to the database and returns the document diff --git a/MongoDB/src/Database.cpp b/MongoDB/src/Database.cpp index d34246851..6b96cd0dc 100644 --- a/MongoDB/src/Database.cpp +++ b/MongoDB/src/Database.cpp @@ -69,6 +69,44 @@ double Database::count(Connection& connection, const std::string& collectionName } +Poco::MongoDB::Document::Ptr Database::ensureIndex(Connection& connection, const std::string& collection, const std::string& indexName, Poco::MongoDB::Document::Ptr keys, bool unique, bool background, int version, int ttl) +{ + Poco::MongoDB::Document::Ptr index = new Poco::MongoDB::Document(); + index->add("ns", _dbname + ".players"); + index->add("name", indexName); + index->add("key", keys); + + if ( version > 0 ) + { + index->add("version", version); + } + + if ( unique ) + { + index->add("unique", true); + } + + if ( background ) + { + index->add("background", true); + } + + if ( ttl > 0 ) + { + index->add("expireAfterSeconds", ttl); + } + + Poco::SharedPtr insertRequest = createInsertRequest("system.indexes"); + insertRequest->documents().push_back(index); + connection.sendRequest(*insertRequest); + + insertRequest->documents().push_back(index); + connection.sendRequest(*insertRequest); + + return getLastErrorDoc(connection); +} + + Document::Ptr Database::getLastErrorDoc(Connection& connection) const { Document::Ptr errorDoc; From 99cd51d727f46a482cad676a69f30978aba68b3e Mon Sep 17 00:00:00 2001 From: fbraem Date: Fri, 22 Feb 2013 19:30:14 +0100 Subject: [PATCH 07/13] Use addNewDocument when possible, add sample for ensureIndex --- MongoDB/samples/SQLToMongo/src/main.cpp | 44 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/MongoDB/samples/SQLToMongo/src/main.cpp b/MongoDB/samples/SQLToMongo/src/main.cpp index 931cf6091..617204e3e 100644 --- a/MongoDB/samples/SQLToMongo/src/main.cpp +++ b/MongoDB/samples/SQLToMongo/src/main.cpp @@ -170,13 +170,8 @@ void sample5(Poco::MongoDB::Connection& connection) Poco::MongoDB::Cursor cursor("sample", "players"); // When orderby is needed, use 2 separate documents in the query selector - Poco::MongoDB::Document::Ptr query = new Poco::MongoDB::Document(); - query->add("birthyear", 1987); - cursor.query().selector().add("$query", query); - - Poco::MongoDB::Document::Ptr order = new Poco::MongoDB::Document(); - order->add("lastname", 0); - cursor.query().selector().add("$orderby", order); + cursor.query().selector().addNewDocument("$query").add("birthyear", 1987); + cursor.query().selector().addNewDocument("$orderby").add("lastname", 0); Poco::MongoDB::ResponseMessage& response = cursor.next(connection); while(1) @@ -205,11 +200,9 @@ void sample6(Poco::MongoDB::Connection& connection) Poco::MongoDB::Cursor cursor("sample", "players"); - Poco::MongoDB::Document::Ptr oper = new Poco::MongoDB::Document(); - oper->add("$gt", 1969); - oper->add("$lte", 1980); - - cursor.query().selector().add("birthyear", oper); + cursor.query().selector().addNewDocument("birthyear") + .add("$gt", 1969) + .add("$lte", 1980); Poco::MongoDB::ResponseMessage& response = cursor.next(connection); while(1) @@ -231,6 +224,32 @@ void sample6(Poco::MongoDB::Connection& connection) } +// CREATE INDEX playername +// ON players(lastname) +void sample7(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 7 ***" << std::endl; + + Poco::MongoDB::Database db("sample"); + Poco::MongoDB::Document::Ptr keys = new Poco::MongoDB::Document(); + keys->add("lastname", 1); + Poco::MongoDB::Document::Ptr errorDoc = db.ensureIndex(connection, "players", "lastname", keys); + + /* Sample above is the same as the following code: + Poco::MongoDB::Document::Ptr index = new Poco::MongoDB::Document(); + index->add("ns", "sample.players"); + index->add("name", "lastname"); + index->addNewDocument("key").add("lastname", 1); + + Poco::SharedPtr insertRequest = db.createInsertRequest("system.indexes"); + insertRequest->documents().push_back(index); + connection.sendRequest(*insertRequest); + Poco::MongoDB::Document::Ptr errorDoc = db.getLastErrorDoc(connection); + */ + std::cout << errorDoc->toString(2); +} + + int main(int argc, char** argv) { Poco::MongoDB::Connection connection("localhost", 27017); @@ -240,6 +259,7 @@ int main(int argc, char** argv) sample4(connection); sample5(connection); sample6(connection); + sample7(connection); return 0; } From 382dbd5637c5034666f098d3792fc613f802b472 Mon Sep 17 00:00:00 2001 From: fbraem Date: Sat, 23 Feb 2013 17:36:10 +0100 Subject: [PATCH 08/13] Add addNewDocument method --- MongoDB/include/Poco/MongoDB/InsertRequest.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MongoDB/include/Poco/MongoDB/InsertRequest.h b/MongoDB/include/Poco/MongoDB/InsertRequest.h index a520cda58..995aebc78 100644 --- a/MongoDB/include/Poco/MongoDB/InsertRequest.h +++ b/MongoDB/include/Poco/MongoDB/InsertRequest.h @@ -69,6 +69,12 @@ public: /// Destructor + Document& addNewDocument(); + /// Adds a new document for insertion. A reference to the empty document is + /// returned. InsertRequest is the owner of the Document and will free it + /// on destruction. + + Document::Vector& documents(); /// Returns the documents to insert into the database @@ -87,6 +93,16 @@ private: }; +inline Document& InsertRequest::addNewDocument() +{ + Document::Ptr doc = new Document(); + + _documents.push_back(doc); + + return *doc; +} + + inline Document::Vector& InsertRequest::documents() { return _documents; From 6a8b2c5a48a2021cf0f090a8e48c985d64216ccc Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 27 Feb 2013 18:51:05 +0100 Subject: [PATCH 09/13] Add some handy "short-cut" functions --- .../include/Poco/MongoDB/ResponseMessage.h | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/MongoDB/include/Poco/MongoDB/ResponseMessage.h b/MongoDB/include/Poco/MongoDB/ResponseMessage.h index 1a55863ca..1560c40ba 100644 --- a/MongoDB/include/Poco/MongoDB/ResponseMessage.h +++ b/MongoDB/include/Poco/MongoDB/ResponseMessage.h @@ -60,14 +60,6 @@ public: /// Destructor - void read(std::istream& istr); - /// Reads the response from the stream - - - Document::Vector& documents(); - /// Returns the retrieved documents - - Int64 cursorID() const; /// Returns the cursor id @@ -75,6 +67,27 @@ public: void clear(); /// Clears the response + + size_t count() const; + /// Returns the number of documents in the response + + + Document::Vector& documents(); + /// Returns the retrieved documents + + + bool empty() const; + /// Returns true when the response doesn't contain any documents + + + bool hasDocuments() const; + /// Returns true when there is at least one document + + + void read(std::istream& istr); + /// Reads the response from the stream + + private: Int32 _responseFlags; @@ -93,9 +106,15 @@ private: }; -inline Document::Vector& ResponseMessage::documents() +inline size_t ResponseMessage::count() const { - return _documents; + return _documents.size(); +} + + +inline bool ResponseMessage::empty() const +{ + return _documents.size() == 0; } @@ -105,6 +124,17 @@ inline Int64 ResponseMessage::cursorID() const } +inline Document::Vector& ResponseMessage::documents() +{ + return _documents; +} + + +inline bool ResponseMessage::hasDocuments() const +{ + return _documents.size() > 0; +} + }} // Namespace Poco::MongoDB #endif //_MongoDB_ResponseMessage_included From 2d3e78146d4e924fbce9c154b235cc2f2de5a624 Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 27 Feb 2013 18:51:55 +0100 Subject: [PATCH 10/13] Add createCommand method and rearrange code --- MongoDB/include/Poco/MongoDB/Database.h | 16 ++++++++++++++-- MongoDB/src/Database.cpp | 12 ++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/MongoDB/include/Poco/MongoDB/Database.h b/MongoDB/include/Poco/MongoDB/Database.h index 7848ae3e9..9da958ce2 100644 --- a/MongoDB/include/Poco/MongoDB/Database.h +++ b/MongoDB/include/Poco/MongoDB/Database.h @@ -66,8 +66,8 @@ public: /// the command fails, -1 is returned. - Poco::SharedPtr createQueryRequest(const std::string& collectionName) const; - /// Creates a QueryRequest. The collectionname must not contain the database name! + Poco::SharedPtr createCommand() const; + /// Creates a QueryRequest for a command. Poco::SharedPtr createCountRequest(const std::string& collectionName) const; @@ -80,6 +80,10 @@ public: /// The collectionname must not contain the database name! + Poco::SharedPtr createQueryRequest(const std::string& collectionName) const; + /// Creates a QueryRequest. The collectionname must not contain the database name! + + Poco::MongoDB::Document::Ptr ensureIndex(Connection& connection, const std::string& collection, const std::string& indexName, Poco::MongoDB::Document::Ptr keys, bool unique = false, bool background = false, int version = 0, int ttl = 0); /// Creates an index. The document returned is the result of a getLastError call. /// For more info look at the ensureIndex information on the MongoDB website. @@ -97,6 +101,14 @@ private: std::string _dbname; }; + +inline Poco::SharedPtr Database::createCommand() const +{ + Poco::SharedPtr cmd = createQueryRequest("$cmd"); + cmd->setNumberToReturn(1); + return cmd; +} + }} // Namespace Poco::MongoDB #endif // _MongoDB_Database_included diff --git a/MongoDB/src/Database.cpp b/MongoDB/src/Database.cpp index 6b96cd0dc..d4a1c454c 100644 --- a/MongoDB/src/Database.cpp +++ b/MongoDB/src/Database.cpp @@ -138,12 +138,6 @@ std::string Database::getLastError(Connection& connection) const } -Poco::SharedPtr Database::createQueryRequest(const std::string& collectionName) const -{ - return new Poco::MongoDB::QueryRequest(_dbname + '.' + collectionName); -} - - Poco::SharedPtr Database::createCountRequest(const std::string& collectionName) const { Poco::SharedPtr request = createQueryRequest("$cmd"); @@ -159,4 +153,10 @@ Poco::SharedPtr Database::createInsertRequest(cons } +Poco::SharedPtr Database::createQueryRequest(const std::string& collectionName) const +{ + return new Poco::MongoDB::QueryRequest(_dbname + '.' + collectionName); +} + + }} // Namespace Poco::MongoDB From d1b318b80698496353c6695547d30c4d42637c51 Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 27 Feb 2013 19:50:05 +0100 Subject: [PATCH 11/13] Add size method --- MongoDB/include/Poco/MongoDB/Document.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MongoDB/include/Poco/MongoDB/Document.h b/MongoDB/include/Poco/MongoDB/Document.h index de6884553..6737fc551 100644 --- a/MongoDB/include/Poco/MongoDB/Document.h +++ b/MongoDB/include/Poco/MongoDB/Document.h @@ -207,6 +207,10 @@ public: /// Reads a document from the reader + size_t size() const; + /// Returns the number of elements in the document. + + virtual std::string toString(int indent = 0) const; /// Returns a String representation of the document. @@ -263,6 +267,12 @@ inline bool Document::exists(const std::string& name) } +inline size_t Document::size() const +{ + return _elements.size(); +} + + // BSON Embedded Document // spec: document template<> From ee360d307c16405b882b72b0d7751df4fba0abc6 Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 27 Feb 2013 19:51:33 +0100 Subject: [PATCH 12/13] Add methods that turns a numeric index into a string for getting the element (an array is actually a document) --- MongoDB/include/Poco/MongoDB/Array.h | 36 ++++++++++++++++++++++++++++ MongoDB/src/Array.cpp | 7 ++++++ 2 files changed, 43 insertions(+) diff --git a/MongoDB/include/Poco/MongoDB/Array.h b/MongoDB/include/Poco/MongoDB/Array.h index 0a5f417bc..8c42e95fc 100644 --- a/MongoDB/include/Poco/MongoDB/Array.h +++ b/MongoDB/include/Poco/MongoDB/Array.h @@ -38,6 +38,8 @@ #ifndef _MongoDB_Array_included #define _MongoDB_Array_included +#include "Poco/NumberFormatter.h" + #include "Poco/MongoDB/MongoDB.h" #include "Poco/MongoDB/Document.h" @@ -59,6 +61,40 @@ public: /// Destructor + template + T get(int pos) const + /// Returns the element on the given index and tries to convert + /// it to the template type. When the element is not found, a + /// NotFoundException will be thrown. When the element can't be + /// converted a BadCastException will be thrown. + { + return Document::get(Poco::NumberFormatter::format(pos)); + } + + + template + T get(int pos, const T& def) const + /// Returns the element on the given index and tries to convert + /// it to the template type. When the element is not found, or + /// has the wrong type, the def argument will be returned. + { + return Document::get(Poco::NumberFormatter::format(pos), def); + } + + + Element::Ptr get(int pos) const; + /// Returns the element on the given index. + /// An empty element will be returned when the element is not found. + + + template + bool isType(int pos) + /// Returns true when the type of the element equals the TypeId of ElementTrait + { + return Document::isType(Poco::NumberFormatter::format(pos)); + } + + std::string toString(int indent = 0) const; }; diff --git a/MongoDB/src/Array.cpp b/MongoDB/src/Array.cpp index 191ee8d43..64528151b 100644 --- a/MongoDB/src/Array.cpp +++ b/MongoDB/src/Array.cpp @@ -51,6 +51,13 @@ Array::~Array() } +Element::Ptr Array::get(int pos) const +{ + std::string name = Poco::NumberFormatter::format(pos); + return Document::get(name); +} + + std::string Array::toString(int indent) const { std::ostringstream oss; From c52dcc1c2f07a07fcf2b9f3e9e273e66a5c8ca42 Mon Sep 17 00:00:00 2001 From: fbraem Date: Wed, 27 Feb 2013 19:51:44 +0100 Subject: [PATCH 13/13] Add more samples --- MongoDB/samples/SQLToMongo/src/main.cpp | 215 +++++++++++++++++++++--- 1 file changed, 190 insertions(+), 25 deletions(-) diff --git a/MongoDB/samples/SQLToMongo/src/main.cpp b/MongoDB/samples/SQLToMongo/src/main.cpp index 617204e3e..eae1dbb74 100644 --- a/MongoDB/samples/SQLToMongo/src/main.cpp +++ b/MongoDB/samples/SQLToMongo/src/main.cpp @@ -36,6 +36,7 @@ #include "Poco/MongoDB/Connection.h" #include "Poco/MongoDB/Database.h" #include "Poco/MongoDB/Cursor.h" +#include "Poco/MongoDB/Array.h" // INSERT INTO players // VALUES( "Messi", "Lionel", 1987) @@ -44,35 +45,113 @@ void sample1(Poco::MongoDB::Connection& connection) std::cout << "*** SAMPLE 1 ***" << std::endl; Poco::MongoDB::Database db("sample"); - Poco::SharedPtr insertUserRequest = db.createInsertRequest("players"); + Poco::SharedPtr insertPlayerRequest = db.createInsertRequest("players"); // With one insert request, we can add multiple documents + insertPlayerRequest->addNewDocument() + .add("lastname", "Valdes") + .add("firstname", "Victor") + .add("birthyear", 1982); + insertPlayerRequest->addNewDocument() + .add("lastname", "Alves") + .add("firstname", "Daniel") + .add("birthyear", 1983); + insertPlayerRequest->addNewDocument() + .add("lastname", "Bartra") + .add("firstname", "Marc") + .add("birthyear", 1991); + insertPlayerRequest->addNewDocument() + .add("lastname", "Alba") + .add("firstname", "Jordi") + .add("birthyear", 1989); + insertPlayerRequest->addNewDocument() + .add("lastname", "Montoya") + .add("firstname", "Martin") + .add("birthyear", 1991); + insertPlayerRequest->addNewDocument() + .add("lastname", "Abidal") + .add("firstname", "Eric") + .add("birthyear", 1979); + insertPlayerRequest->addNewDocument() + .add("lastname", "Fontas") + .add("firstname", "Andreu") + .add("birthyear", 1989); + insertPlayerRequest->addNewDocument() + .add("lastname", "Messi") + .add("firstname", "Lionel") + .add("birthyear", 1987); + insertPlayerRequest->addNewDocument() + .add("lastname", "Puyol") + .add("firstname", "Carles") + .add("birthyear", 1978); + insertPlayerRequest->addNewDocument() + .add("lastname", "Piqué") + .add("firstname", "Gerard") + .add("birthyear", 1987); + insertPlayerRequest->addNewDocument() + .add("lastname", "Muniesa") + .add("firstname", "Marc") + .add("birthyear", 1992); + insertPlayerRequest->addNewDocument() + .add("lastname", "Fabrégas") + .add("firstname", "Cesc") + .add("birthyear", 1987); + insertPlayerRequest->addNewDocument() + .add("lastname", "Hernandez") + .add("firstname", "Xavi") + .add("birthyear", 1980); + insertPlayerRequest->addNewDocument() + .add("lastname", "Iniesta") + .add("firstname", "Andres") + .add("birthyear", 1984); + insertPlayerRequest->addNewDocument() + .add("lastname", "Alcantara") + .add("firstname", "Thiago") + .add("birthyear", 1991); + insertPlayerRequest->addNewDocument() + .add("lastname", "Dos Santos") + .add("firstname", "Jonathan") + .add("birthyear", 1990); + insertPlayerRequest->addNewDocument() + .add("lastname", "Mascherano") + .add("firstname", "Javier") + .add("birthyear", 1984); + insertPlayerRequest->addNewDocument() + .add("lastname", "Busquets") + .add("firstname", "Sergio") + .add("birthyear", 1988); + insertPlayerRequest->addNewDocument() + .add("lastname", "Adriano") + .add("firstname", "") + .add("birthyear", 1984); + insertPlayerRequest->addNewDocument() + .add("lastname", "Song") + .add("firstname", "Alex") + .add("birthyear", 1987); + insertPlayerRequest->addNewDocument() + .add("lastname", "Villa") + .add("firstname", "David") + .add("birthyear", 1981); + insertPlayerRequest->addNewDocument() + .add("lastname", "Sanchez") + .add("firstname", "Alexis") + .add("birthyear", 1988); + insertPlayerRequest->addNewDocument() + .add("lastname", "Pedro") + .add("firstname", "") + .add("birthyear", 1987); + insertPlayerRequest->addNewDocument() + .add("lastname", "Cuenca") + .add("firstname", "Isaac") + .add("birthyear", 1991); + insertPlayerRequest->addNewDocument() + .add("lastname", "Tello") + .add("firstname", "Cristian") + .add("birthyear", 1991); - Poco::MongoDB::Document::Ptr player = new Poco::MongoDB::Document(); - player->add("lastname", "Messi"); - player->add("firstname", "Lionel"); - player->add("birthyear", 1987); - insertUserRequest->documents().push_back(player); + std::cout << insertPlayerRequest->documents().size() << std::endl; - player = new Poco::MongoDB::Document(); - player->add("lastname", "Valdes"); - player->add("firstname", "Victor"); - player->add("birthyear", 1982); - insertUserRequest->documents().push_back(player); - - player = new Poco::MongoDB::Document(); - player->add("lastname", "Puyol"); - player->add("firstname", "Carles"); - player->add("birthyear", 1978); - insertUserRequest->documents().push_back(player); - - player = new Poco::MongoDB::Document(); - player->add("lastname", "Piqué"); - player->add("firstname", "Gerard"); - player->add("birthyear", 1987); - insertUserRequest->documents().push_back(player); - - connection.sendRequest(*insertUserRequest); + connection.sendRequest(*insertPlayerRequest); std::string lastError = db.getLastError(connection); if ( !lastError.empty() ) { @@ -250,9 +329,92 @@ void sample7(Poco::MongoDB::Connection& connection) } +// SELECT * FROM players LIMIT 10 SKIP 20 +void sample8(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 8 ***" << std::endl; + + Poco::MongoDB::Cursor cursor("sample", "players"); + cursor.query().setNumberToReturn(10); + cursor.query().setNumberToSkip(20); + Poco::MongoDB::ResponseMessage& response = cursor.next(connection); + while(1) + { + for(Poco::MongoDB::Document::Vector::const_iterator it = response.documents().begin(); it != response.documents().end(); ++it) + { + std::cout << (*it)->get("lastname") << ' ' << (*it)->get("firstname") << " (" << (*it)->get("birthyear") << ')' << std::endl; + } + + // When the cursorID is 0, there are no documents left, so break out ... + if ( response.cursorID() == 0 ) + { + break; + } + + // Get the next bunch of documents + response = cursor.next(connection); + }; +} + +// SELECT * FROM players LIMIT 1 +void sample9(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 9 ***" << std::endl; + + // QueryRequest can be used directly + Poco::MongoDB::QueryRequest query("sample.players"); + query.setNumberToReturn(1); + Poco::MongoDB::ResponseMessage response; + connection.sendRequest(query, response); + if ( response.hasDocuments() ) + { + std::cout << response.documents()[0]->toString(2); + } + + // QueryRequest can be created using the Database class + Poco::MongoDB::Database db("sample"); + Poco::SharedPtr queryPtr = db.createQueryRequest("players"); + queryPtr->setNumberToReturn(1); + connection.sendRequest(*queryPtr, response); + if ( response.hasDocuments() ) + { + std::cout << response.documents()[0]->toString(2); + } +} + +// SELECT DISTINCT birthyear FROM players WHERE birthyear > 1980 +void sample10(Poco::MongoDB::Connection& connection) +{ + std::cout << "*** SAMPLE 10 ***" << std::endl; + + Poco::MongoDB::Database db("sample"); + Poco::SharedPtr command = db.createCommand(); + std::cout << command->fullCollectionName() << std::endl; + + command->selector() + .add("distinct", "players") + .add("key", "birthyear") + .addNewDocument("query") + .addNewDocument("birthyear") + .add("$gt", 1980); + + Poco::MongoDB::ResponseMessage response; + connection.sendRequest(*command, response); + if ( response.hasDocuments() ) + { + Poco::MongoDB::Array::Ptr values = response.documents()[0]->get("values"); + for(int i = 0; i < values->size(); ++i ) + { + std::cout << values->get(i) << std::endl; + } + } + +} + int main(int argc, char** argv) { Poco::MongoDB::Connection connection("localhost", 27017); + sample1(connection); sample2(connection); sample3(connection); @@ -260,6 +422,9 @@ int main(int argc, char** argv) sample5(connection); sample6(connection); sample7(connection); + sample8(connection); + sample9(connection); + sample10(connection); return 0; }