enh(MongoDB): Update samples and replica set readme.

This commit is contained in:
Matej Kenda
2025-12-05 17:54:03 +01:00
parent 12587d19dc
commit 6c2ee63455
5 changed files with 185 additions and 67 deletions

View File

@@ -1,6 +1,18 @@
# MongoDB Replica Set Examples
This directory contains examples demonstrating Poco::MongoDB replica set support.
This directory contains comprehensive examples demonstrating Poco::MongoDB replica set support with automatic failover, read preferences, and connection pooling.
**Minimum MongoDB Version**: MongoDB 5.1 or later (for replica set features)
## Examples Overview
| Sample | Description |
|--------|-------------|
| **ReplicaSetMonitor** | Production-ready monitoring tool for deployment verification and continuous health monitoring |
| **ReplicaSet** | Feature demonstrations with multiple commands (basic, readpref, failover, pool, topology) |
| **URIExample** | MongoDB URI parsing and connection demonstration |
---
## ReplicaSetMonitor - Deployment Health Check Tool
@@ -271,16 +283,18 @@ Demonstrates MongoDB URI parsing and connection to replica sets.
./URIExample 'mongodb://mongo1:27017,mongo2:27017/?replicaSet=rs0&readPreference=primaryPreferred'
# With custom timeouts and heartbeat
./URIExample 'mongodb://host1:27017,host2:27017/?replicaSet=rs0&connectTimeoutMS=5000&socketTimeoutMS=30000&heartbeatFrequencyMS=5000'
./URIExample 'mongodb://host1:27017,host2:27017/?replicaSet=rs0&connectTimeoutMS=5000&socketTimeoutMS=30000&heartbeatFrequency=5'
```
### Supported URI Options
- `replicaSet=name` - Replica set name
- `readPreference=mode` - Read preference (primary|primaryPreferred|secondary|secondaryPreferred|nearest)
- `connectTimeoutMS=ms` - Connection timeout in milliseconds
- `socketTimeoutMS=ms` - Socket timeout in milliseconds
- `heartbeatFrequencyMS=ms` - Heartbeat frequency in milliseconds
- `connectTimeoutMS=ms` - Connection timeout in milliseconds (for custom SocketFactory implementations)
- `socketTimeoutMS=ms` - Socket timeout in milliseconds (for custom SocketFactory implementations)
- `heartbeatFrequency=seconds` - Heartbeat frequency in seconds (default: 10)
- `reconnectRetries=n` - Number of reconnection retries (default: 10)
- `reconnectDelay=seconds` - Delay between reconnection attempts in seconds (default: 1)
### Example Output
@@ -388,7 +402,7 @@ ReadPreference pref(ReadPreference::Nearest, tags);
```cpp
ReplicaSet::Config config;
config.heartbeatFrequency = Poco::Timespan(30, 0); // 30 seconds
config.heartbeatFrequencySeconds = 30; // 30 seconds (default: 10)
```
### Disable Background Monitoring
@@ -398,6 +412,14 @@ ReplicaSet::Config config;
config.enableMonitoring = false; // Manual topology refresh only
```
### Custom Reconnection Settings
```cpp
ReplicaSet::Config config;
config.serverReconnectRetries = 5; // Number of retries (default: 10)
config.serverReconnectDelaySeconds = 2; // Delay between retries in seconds (default: 1)
```
---
## Additional Resources

View File

@@ -364,7 +364,7 @@ void topologyExample()
ReplicaSet::Config config;
config.setName = setName;
config.seeds = parseHosts(hostsStr);
config.heartbeatFrequency = Poco::Timespan(5, 0); // 5 seconds
config.heartbeatFrequencySeconds = 5; // 5 seconds
config.enableMonitoring = true;
ReplicaSet rs(config);
@@ -408,7 +408,7 @@ void topologyExample()
}
std::cout << std::endl;
std::cout << "Background monitoring is active (heartbeat every " << config.heartbeatFrequency.totalSeconds() << "s)" << std::endl;
std::cout << "Background monitoring is active (heartbeat every " << config.heartbeatFrequencySeconds << "s)" << std::endl;
std::cout << "Topology will be automatically updated as servers change state." << std::endl;
}
catch (const Exception& e)

View File

@@ -321,7 +321,7 @@ void runMonitor(const MonitorConfig& config)
rsConfig.seeds = config.seeds;
rsConfig.readPreference = ReadPreference(ReadPreference::PrimaryPreferred);
rsConfig.enableMonitoring = true;
rsConfig.heartbeatFrequency = Poco::Timespan(5, 0); // 5 seconds
rsConfig.heartbeatFrequencySeconds = 5; // 5 seconds
std::cout << "Connecting to replica set: " << config.setName << std::endl;
std::cout << "Seed servers: ";

View File

@@ -1,9 +1,19 @@
//
// main.cpp
// SQLToMongo.cpp
//
// This sample shows SQL to MongoDB Shell to C++ examples using OP_MSG wire protocol.
// This sample demonstrates basic MongoDB operations using the Poco::MongoDB library
// with the OP_MSG wire protocol. Each function shows how to translate common SQL
// operations to MongoDB commands.
//
// Copyright (c) 2013, Applied Informatics Software Engineering GmbH.
// The examples use a "players" collection to demonstrate:
// - INSERT operations (inserting documents)
// - SELECT operations (querying with filters, projections, sorting, limits)
// - UPDATE operations (modifying documents)
// - DELETE operations (removing documents)
// - Creating indexes
// - Distinct queries and aggregations
//
// Copyright (c) 2013-2025, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
@@ -18,11 +28,13 @@
#include "Poco/MongoDB/Array.h"
// INSERT INTO players
// VALUES( "Messi", "Lionel", 1987)
// SQL: INSERT INTO players VALUES ("Valdes", "Victor", 1982), ...
// MongoDB: db.players.insertMany([{...}, {...}])
//
// This sample demonstrates inserting multiple documents at once.
void sample1(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 1 ***" << std::endl;
std::cout << "*** SAMPLE 1: INSERT multiple documents ***" << std::endl;
Poco::MongoDB::Database db("sample");
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
@@ -131,7 +143,7 @@ void sample1(Poco::MongoDB::Connection& connection)
doc->add("lastname", "Tello").add("firstname", "Cristian").add("birthyear", 1991);
docs.push_back(doc);
std::cout << request->documents().size() << std::endl;
std::cout << "Inserting " << request->documents().size() << " player documents..." << std::endl;
Poco::MongoDB::OpMsgMessage response;
connection.sendRequest(*request, response);
@@ -139,13 +151,21 @@ void sample1(Poco::MongoDB::Connection& connection)
{
std::cout << "Error: " << response.body().toString(2) << std::endl;
}
else
{
std::cout << "Successfully inserted " << request->documents().size() << " documents" << std::endl;
}
std::cout << std::endl;
}
// SELECT lastname, birthyear FROM players
// SQL: SELECT lastname, birthyear FROM players
// MongoDB: db.players.find({}, {lastname: 1, birthyear: 1})
//
// This sample demonstrates projection (selecting specific fields).
void sample2(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 2 ***" << std::endl;
std::cout << "*** SAMPLE 2: SELECT with projection (specific fields) ***" << std::endl;
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
@@ -163,13 +183,17 @@ void sample2(Poco::MongoDB::Connection& connection)
}
response = cursor.next(connection);
}
std::cout << std::endl;
}
// SELECT * FROM players
// SQL: SELECT * FROM players
// MongoDB: db.players.find({})
//
// This sample demonstrates querying all fields from all documents.
void sample3(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 3 ***" << std::endl;
std::cout << "*** SAMPLE 3: SELECT * (all fields) ***" << std::endl;
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
@@ -183,13 +207,17 @@ void sample3(Poco::MongoDB::Connection& connection)
}
response = cursor.next(connection);
}
std::cout << std::endl;
}
// SELECT * FROM players WHERE birthyear = 1978
// SQL: SELECT * FROM players WHERE birthyear = 1978
// MongoDB: db.players.find({birthyear: 1978})
//
// This sample demonstrates filtering with a WHERE clause (exact match).
void sample4(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 4 ***" << std::endl;
std::cout << "*** SAMPLE 4: SELECT with WHERE clause (filter) ***" << std::endl;
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
@@ -204,13 +232,17 @@ void sample4(Poco::MongoDB::Connection& connection)
}
response = cursor.next(connection);
}
std::cout << std::endl;
}
// SELECT * FROM players WHERE birthyear = 1987 ORDER BY name
// SQL: SELECT * FROM players WHERE birthyear = 1987 ORDER BY lastname
// MongoDB: db.players.find({birthyear: 1987}).sort({lastname: 1})
//
// This sample demonstrates sorting results with ORDER BY.
void sample5(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 5 ***" << std::endl;
std::cout << "*** SAMPLE 5: SELECT with ORDER BY (sorting) ***" << std::endl;
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
@@ -226,13 +258,17 @@ void sample5(Poco::MongoDB::Connection& connection)
}
response = cursor.next(connection);
}
std::cout << std::endl;
}
// SELECT * FROM players WHERE birthyear > 1969 and birthyear <= 1980
// SQL: SELECT * FROM players WHERE birthyear > 1969 AND birthyear <= 1980
// MongoDB: db.players.find({birthyear: {$gt: 1969, $lte: 1980}})
//
// This sample demonstrates range queries with comparison operators.
void sample6(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 6 ***" << std::endl;
std::cout << "*** SAMPLE 6: SELECT with range query ($gt, $lte) ***" << std::endl;
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
@@ -250,28 +286,43 @@ void sample6(Poco::MongoDB::Connection& connection)
}
response = cursor.next(connection);
}
std::cout << std::endl;
}
// CREATE INDEX playername
// ON players(lastname)
// SQL: CREATE INDEX playername ON players(lastname)
// MongoDB: db.players.createIndex({lastname: 1})
//
// This sample demonstrates creating an index on a collection.
void sample7(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 7 ***" << std::endl;
std::cout << "*** SAMPLE 7: CREATE INDEX ***" << std::endl;
Poco::MongoDB::Database db("sample");
Poco::MongoDB::Document::Ptr keys = new Poco::MongoDB::Document();
keys->add("lastname", 1);
Poco::MongoDB::Document::Ptr resultDoc = db.ensureIndex(connection, "players", "lastname", keys);
std::cout << resultDoc->toString(2);
// Create index on lastname field (ascending: true)
Poco::MongoDB::Database::IndexedFields indexedFields;
indexedFields.push_back(std::make_tuple("lastname", true)); // true = ascending
Poco::MongoDB::Document::Ptr resultDoc = db.createIndex(
connection,
"players", // collection name
indexedFields, // fields to index
"lastname_idx" // index name
);
std::cout << "Index created: " << resultDoc->toString(2) << std::endl;
std::cout << std::endl;
}
// SELECT * FROM players LIMIT 10 SKIP 20
// SQL: SELECT * FROM players LIMIT 10 OFFSET 20
// MongoDB: db.players.find({}).skip(20).limit(10)
//
// This sample demonstrates pagination with LIMIT and SKIP.
void sample8(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 8 ***" << std::endl;
std::cout << "*** SAMPLE 8: SELECT with LIMIT and SKIP (pagination) ***" << std::endl;
Poco::MongoDB::OpMsgCursor cursor("sample", "players");
cursor.query().setCommandName(Poco::MongoDB::OpMsgMessage::CMD_FIND);
@@ -288,13 +339,17 @@ void sample8(Poco::MongoDB::Connection& connection)
}
response = cursor.next(connection);
}
std::cout << std::endl;
}
// SELECT * FROM players LIMIT 1
// SQL: SELECT * FROM players LIMIT 1
// MongoDB: db.players.findOne({})
//
// This sample demonstrates fetching a single document.
void sample9(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 9 ***" << std::endl;
std::cout << "*** SAMPLE 9: SELECT LIMIT 1 (single document) ***" << std::endl;
Poco::MongoDB::Database db("sample");
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
@@ -305,15 +360,20 @@ void sample9(Poco::MongoDB::Connection& connection)
connection.sendRequest(*request, response);
if (!response.documents().empty())
{
std::cout << "First document:" << std::endl;
std::cout << response.documents()[0]->toString(2) << std::endl;
}
std::cout << std::endl;
}
// SELECT DISTINCT birthyear FROM players WHERE birthyear > 1980
// SQL: SELECT DISTINCT birthyear FROM players WHERE birthyear > 1980
// MongoDB: db.players.distinct("birthyear", {birthyear: {$gt: 1980}})
//
// This sample demonstrates the distinct command with a filter.
void sample10(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 10 ***" << std::endl;
std::cout << "*** SAMPLE 10: SELECT DISTINCT with WHERE ***" << std::endl;
Poco::MongoDB::Database db("sample");
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
@@ -329,18 +389,25 @@ void sample10(Poco::MongoDB::Connection& connection)
if (response.responseOk())
{
Poco::MongoDB::Array::Ptr values = response.body().get<Poco::MongoDB::Array::Ptr>("values");
std::cout << "Distinct birthyears (> 1980): ";
for (std::size_t i = 0; i < values->size(); ++i)
{
std::cout << values->get<int>(i) << std::endl;
if (i > 0) std::cout << ", ";
std::cout << values->get<int>(i);
}
std::cout << std::endl;
}
std::cout << std::endl;
}
// SELECT COUNT(*) FROM players WHERE birthyear > 1980
// SQL: SELECT COUNT(*) FROM players WHERE birthyear > 1980
// MongoDB: db.players.countDocuments({birthyear: {$gt: 1980}})
//
// This sample demonstrates the count command with a filter.
void sample11(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 11 ***" << std::endl;
std::cout << "*** SAMPLE 11: SELECT COUNT with WHERE ***" << std::endl;
Poco::MongoDB::Database db("sample");
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
@@ -355,15 +422,19 @@ void sample11(Poco::MongoDB::Connection& connection)
if (response.responseOk())
{
std::cout << "Count: " << response.body().getInteger("n") << std::endl;
std::cout << "Count of players born after 1980: " << response.body().getInteger("n") << std::endl;
}
std::cout << std::endl;
}
// UPDATE players SET birthyear = birthyear + 1 WHERE firstname = 'Victor'
// SQL: UPDATE players SET birthyear = birthyear + 1 WHERE firstname = 'Victor'
// MongoDB: db.players.updateMany({firstname: "Victor"}, {$inc: {birthyear: 1}})
//
// This sample demonstrates the update command with the $inc operator.
void sample12(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 12 ***" << std::endl;
std::cout << "*** SAMPLE 12: UPDATE with increment operator ***" << std::endl;
Poco::MongoDB::Database db("sample");
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
@@ -377,14 +448,18 @@ void sample12(Poco::MongoDB::Connection& connection)
Poco::MongoDB::OpMsgMessage response;
connection.sendRequest(*request, response);
std::cout << "Response: " << response.body().toString(2) << std::endl;
std::cout << "Update response: " << response.body().toString(2) << std::endl;
std::cout << std::endl;
}
// DELETE players WHERE firstname = 'Victor'
// SQL: DELETE FROM players WHERE firstname = 'Victor'
// MongoDB: db.players.deleteMany({firstname: "Victor"})
//
// This sample demonstrates the delete command.
void sample13(Poco::MongoDB::Connection& connection)
{
std::cout << "*** SAMPLE 13 ***" << std::endl;
std::cout << "*** SAMPLE 13: DELETE ***" << std::endl;
Poco::MongoDB::Database db("sample");
Poco::SharedPtr<Poco::MongoDB::OpMsgMessage> request = db.createOpMsgMessage("players");
@@ -398,33 +473,54 @@ void sample13(Poco::MongoDB::Connection& connection)
Poco::MongoDB::OpMsgMessage response;
connection.sendRequest(*request, response);
std::cout << "Response: " << response.body().toString(2) << std::endl;
std::cout << "Delete response: " << response.body().toString(2) << std::endl;
std::cout << std::endl;
}
int main(int argc, char** argv)
{
// Connect to MongoDB server
// For replica set connections, see the ReplicaSet samples
Poco::MongoDB::Connection connection("localhost", 27017);
try
{
sample1(connection);
sample2(connection);
sample3(connection);
sample4(connection);
sample5(connection);
sample6(connection);
sample7(connection);
sample8(connection);
sample9(connection);
sample10(connection);
sample11(connection);
sample12(connection);
sample13(connection);
std::cout << "==================================================" << std::endl;
std::cout << "Poco::MongoDB SQL to MongoDB Examples" << std::endl;
std::cout << "==================================================" << std::endl;
std::cout << std::endl;
std::cout << "This sample demonstrates how to translate SQL" << std::endl;
std::cout << "operations to MongoDB using the OP_MSG protocol." << std::endl;
std::cout << std::endl;
std::cout << "Connected to: localhost:27017" << std::endl;
std::cout << "Database: sample" << std::endl;
std::cout << "Collection: players" << std::endl;
std::cout << std::endl;
sample1(connection); // INSERT multiple documents
sample2(connection); // SELECT with projection (specific fields)
sample3(connection); // SELECT * (all fields)
sample4(connection); // SELECT with WHERE clause (filter)
sample5(connection); // SELECT with ORDER BY (sorting)
sample6(connection); // SELECT with range query ($gt, $lte)
sample7(connection); // CREATE INDEX
sample8(connection); // SELECT with LIMIT and SKIP (pagination)
sample9(connection); // SELECT LIMIT 1 (single document)
sample10(connection); // SELECT DISTINCT with WHERE
sample11(connection); // SELECT COUNT with WHERE
sample12(connection); // UPDATE with increment operator
sample13(connection); // DELETE
std::cout << std::endl;
std::cout << "==================================================" << std::endl;
std::cout << "All samples completed successfully!" << std::endl;
std::cout << "==================================================" << std::endl;
}
catch (Poco::Exception& exc)
{
std::cerr << exc.displayText() << std::endl;
std::cerr << "ERROR: " << exc.displayText() << std::endl;
return 1;
}
return 0;

View File

@@ -379,7 +379,7 @@ void ReplicaSet::updateTopologyFromHello(const Net::SocketAddress& address) noex
// must be configured during socket creation via custom SocketFactory.
// Send hello command
OpMsgMessage request("admin", "");
OpMsgMessage request("admin"s, ""s);
request.setCommandName(OpMsgMessage::CMD_HELLO);
OpMsgMessage response;
@@ -408,7 +408,7 @@ void ReplicaSet::updateTopologyFromHello(const Net::SocketAddress& address) noex
{
// Mark server as unknown
std::lock_guard<std::mutex> lock(_mutex);
_topology.markServerUnknown(address, "Hello command failed");
_topology.markServerUnknown(address, "Hello command failed"s);
}
}
catch (const std::exception& e)
@@ -421,7 +421,7 @@ void ReplicaSet::updateTopologyFromHello(const Net::SocketAddress& address) noex
{
// Mark server as unknown
std::lock_guard<std::mutex> lock(_mutex);
_topology.markServerUnknown(address, "Unknown error");
_topology.markServerUnknown(address, "Unknown error"s);
}
}
@@ -538,7 +538,7 @@ void ReplicaSet::parseURI(const std::string& uri)
// Parse MongoDB URI: mongodb://[user:pass@]host1:port1,host2:port2[,hostN:portN]/[database][?options]
Poco::URI theURI(uri);
if (theURI.getScheme() != "mongodb")
if (theURI.getScheme() != "mongodb"s)
{
throw Poco::UnknownURISchemeException("Replica set URI must use 'mongodb' scheme");
}