RE:NODE

Formát MongoDB URI: mongodb+srv, hosty a volby

Text: Tým RE:NODE
16 min čtení


MongoDB URI má tvar mongodb://[user:password@]host1[:port1][,host2[:port2],...][/database][?options]. Když nevyplníš nic, všechny oficiální nástroje předpokládají mongodb://localhost:27017. Forma mongodb+srv:// bere přesně jeden název hostu a žádný port, skutečný seznam hostů si vyžádá z DNS a ve výchozím stavu zapne TLS. Několik hostů oddělených čárkami je seed list pro replica set nebo sadu routerů mongos, ne seznam záložních serverů. Driver se připojí k tomu členovi, který uzná za správného - a proto existuje directConnection.

To je celý formát. Zbytek tohoto přehledu popisuje, co jednotlivé části dělají v praxi: výchozí hodnoty, DNS záznamy za +srv, jak driver zachází s více hosty, volby, které mění chování, a kam se řetězec zadává v PyMongo, v driveru pro Node, v mongosh, v konfiguračních souborech .NET a v Compassu. Pro mírnější úvod do částí URI a procentového kódování hesel začni u MongoDB connection strings. Pokud máš URI a server hlásí Authentication failed, jdi raději na průvodce řešením problémů s authSource; tento článek nezopakuje ani jedno z toho.

Formát URI po částech#

code
mongodb://                                   schemeshopapp:pw@                                  credentials (optional)db1.example.net:27017,db2.example.net:27017  host list/shop                                        default database (optional)?replicaSet=rs0&appName=api                  options (optional)

Spojené dohromady bez čehokoli mezi tím vznikne mongodb://shopapp:pw@db1.example.net:27017,db2.example.net:27017/shop?replicaSet=rs0&appName=api.

Pravidla, na která se snadno zapomíná:

  • Port je volitelný a pro každý host, který ho neuvádí, platí výchozí 27017. mongodb://db.example.net a mongodb://db.example.net:27017 jsou totéž.
  • Literál IPv6 patří do hranatých závorek: mongodb://[2001:db8::10]:27017. Bez závorek se dvojtečky v adrese čtou jako oddělovač portu a URI se nepodaří zpracovat.
  • Unixový doménový socket se zapisuje jako jeho procentově zakódovaná cesta na místě hostu: mongodb://%2Ftmp%2Fmongodb-27017.sock. mongod tento socket na Linuxu a macOS vytváří ve výchozím stavu a je to šikovný způsob, jak se připojit ze stejného stroje, aniž bys otevíral jediný TCP port.
  • Lomítko před ? je povinné, kdykoli jsou přítomné volby. mongodb://host:27017/?tls=true je platné; drivery se liší v tom, jak chybějící lomítko zpracují, takže se na to nespoléhej.
  • Názvy voleb nerozlišují velikost písmen (authsource a authSource jsou totéž), hodnoty ano, a booleovské hodnoty jsou řetězce true a false malými písmeny. Některé drivery přijmou i 1, yes a podobně, ale to není přenositelné.
  • Volby se spojují pomocí &. Několik voleb se smí opakovat, například readPreferenceTags; u ostatních platí poslední výskyt, nebo driver vyhodí chybu, podle toho, o jaký driver jde.

Výchozí hodnota: localhost:27017

mongodb://localhost:27017 je řetězec z každého tutoriálu, výchozí hodnota na obrazovce nového připojení v Compassu a to, k čemu se v PyMongo připojí MongoClient() bez argumentů. Má jednu známou past. V Node.js 17 a novějším se může localhost nejprve přeložit na IPv6 adresu ::1, zatímco výchozí mongod poslouchá jen na 127.0.0.1. Výsledkem je connect ECONNREFUSED ::1:27017 u serveru, který běží naprosto v pořádku. Novější verze Node zkoušejí obě rodiny adres a dělají to méně časté, ale spolehlivé řešení je psát v lokálních URI 127.0.0.1 místo localhost, nebo přidat ::1 do net.bindIp v mongod.conf.

Ani mongosh bez argumentů nepoužívá holou výchozí hodnotu. Připojí se k mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000 a tento řetězec vypíše jako první řádek, což je slušná nápověda, které volby stojí za nastavení, když mluvíš pořád jen s jedním lokálním serverem.

Kterou databázi určuje cesta

Část /database je výchozí databáze klienta a výchozí hodnota pro authSource, pokud tato volba chybí. Nic neomezuje: klient připojený s /shop může stále otevřít client["reports"], pokud k ní má uživatel práva. Necháš-li cestu prázdnou, výchozí databáze závisí na driveru (často test nebo žádná), zatímco authSource se vrátí na admin. Ta druhá výchozí hodnota je zdrojem většiny zmatků s autentizací a průvodce uživateli a rolemi vysvětluje, proč uživatelé žijí tam, kde žijí.

mongodb+srv:// a DNS záznamy za ním#

Seed list URI (mongodb+srv://) nahrazuje seznam hostů jedním DNS názvem. Když ho driver uvidí, provede dvě vyhledávání dřív, než otevře jediné spojení.

hosty a portyvýchozí volbyběžné zjišťovánímongodb+srv URIcluster0.example.netSRV dotaz_mongodb._tcp.cluster0...TXT dotazcluster0.example.netSeznam hostů + volbytls=true implicitněČlenové replica setu:27017 každý
Co driver dělá s URI mongodb+srv

Záznam SRV je na _mongodb._tcp.<hostname> a obsahuje jeden cílový hostname a port pro každého člena. Záznam TXT je na samotném hostname a obsahuje volby URI ve tvaru query stringu, například authSource=admin&replicaSet=rs0. Povolené jsou tam jen tři volby - authSource, replicaSet a loadBalanced - a smí existovat jen jeden záznam TXT; víc záznamů je chyba. Cokoli zapsané přímo v URI přebíjí záznam TXT.

Přesně to, co uvidí driver, si můžeš ověřit běžnými DNS nástroji:

bash
$ dig +short SRV _mongodb._tcp.cluster0.example.net0 0 27017 shard-00-00.example.net.0 0 27017 shard-00-01.example.net.0 0 27017 shard-00-02.example.net.$ dig +short TXT cluster0.example.net"authSource=admin&replicaSet=rs0"

Ve Windows dělá stejnou práci nslookup -type=SRV _mongodb._tcp.cluster0.example.net. Pokud dotaz SRV vrátí prázdný výsledek, bude chyba v aplikaci querySrv ENOTFOUND (Node) nebo ConfigurationError zmiňující DNS název (PyMongo) a žádná změna voleb nepomůže.

Pravidla, která z návrhu vyplývají:

  • Přesně jeden hostname a žádný port. Porty pocházejí ze záznamů SRV.
  • Hostnames, které záznam SRV vrátí, musí ležet pod stejnou nadřazenou doménou jako název, na který ses ptal. cluster0.example.net může ukazovat na shard-00-00.example.net, ale ne na db.othercompany.com; drivery takové cíle odmítají z bezpečnostních důvodů. Starší drivery také trvaly na alespoň třech částech názvu oddělených tečkami, což novější verze uvolnily - pokud dvoudílný název selhává, zkontroluj changelog svého driveru.
  • TLS je ve výchozím stavu zapnuté. Přidej tls=false výslovně, pokud opravdu chceš nešifrované spojení, což u +srv skoro nikdy nechceš.
  • directConnection=true se s +srv nesmí použít, protože celý smysl je v tom, že driver objevuje několik serverů.
  • Dvě novější volby ladí vyhledávání: srvServiceName (výchozí mongodb) mění část _mongodb v názvu záznamu a srvMaxHosts omezuje, kolik z vrácených hostů se použije, což je určené pro velké sady routerů mongos.

U sharded clusterů připojených přes mongos drivery záznam SRV pravidelně znovu dotazují a podle změn záznamů routery přidávají nebo vyřazují. U replica setu to nepotřebují, protože set po prvním připojení sám hlásí své členství.

mongodb+srv:// se vyplatí používat, když ty záznamy někdo udržuje za tebe - spravovaný cluster, jehož členové se mění, nebo tvůj vlastní replica set se záznamy, které publikuješ ve své DNS zóně. Pro jediný server se nevyplatí. Jedna databáze se záznamem A a mongodb://db.example.net:27017 je jednodušší, nemá žádná další vyhledávání a selhává méně zajímavými způsoby. DNS records explained popisuje typy A, TXT a SRV, pokud je chceš publikovat sám.

Více hostů a replicaSet#

Seznam hostů oddělených čárkami je seed list. Driver se připojí k hostům, které dostal, každého z nich se zeptá na aktuální pohled replica setu na sebe sama (příkaz hello) a od té chvíle pracuje s tím, co říká server, ne s tím, co je v URI.

code
mongodb://db1.example.net:27017,db2.example.net:27017,db3.example.net:27017/shop?replicaSet=rs0

Co to znamená v praxi:

  • Nemusíš vypisovat každého člena. Ke zjišťování stačí jeden dostupný člen, ale když uvedeš všechny, start funguje i tehdy, když je první z nich vypnutý.
  • Pořadí hostů nerozhoduje o tom, kam půjdou zápisy. Zápisy vždy jdou na aktuální primary; čtení jdou tam, kam je pošle readPreference.
  • replicaSet se musí shodovat se skutečným názvem setu (hodnota _id zadaná do rs.initiate()). Člen hlásící jiný název setu se z topologie vyřadí, a pokud se vyřadí všichni, dostaneš timeout při výběru serveru místo jasné zprávy. Skutečný název ti prozradí db.hello().setName v mongosh.
  • Hostnames, která driver nakonec používá, jsou ta z konfigurace replica setu, ne ta z tvého URI. Pokud byl set inicializován s localhost:27017 nebo s názvy kontejnerů interními pro Docker, klient mimo tu síť objeví hostnames, která nedokáže přeložit, a po úspěšném prvním kontaktu vyprší časový limit. Oprav hostnames členů v konfiguraci replica setu pomocí rs.reconfig(); neobcházej to na straně klienta.

U sharded clusteru seznam hostů místo toho pojmenovává routery mongos, volba replicaSet neexistuje a driver rozkládá operace mezi routery, které dosáhne, přičemž dává přednost těm s nejnižší latencí.

directConnection

directConnection=true říká driveru, aby mluvil jen s jediným hostem v URI a přeskočil zjišťování. Je povolené jen s jedním hostem a nikdy s +srv. Použij ho, když:

  • Se chceš připojit ke konkrétnímu členovi, obvykle k secondary, kvůli údržbě nebo kvůli spuštění dotazu bez zásahu do primary.
  • Hostnames nakonfigurovaná v replica setu jsou z tvého místa nedostupná, například při SSH tunelu k jednomu členovi. SSH tunnels and port forwarding popisuje takové nastavení.

Výchozí hodnota je důležitá a změnila se. V PyMongo 4 a v driveru pro Node od verze 4.0 je directConnection ve výchozím stavu false, takže URI s jediným hostem, který je náhodou členem replica setu, spustí zjišťování: driver najde primary a pošle zápisy tam. PyMongo 3 se u jednoho hostu choval, jako by bylo true. Kód, který po upgradu spoléhal na „připoj se jen k tomu stroji“, najednou mluví s jiným serverem, takže ho nastav výslovně, kdykoli na rozdílu záleží. U standalone serveru, který nehlásí žádný replica set, skončí obě hodnoty na stejném místě.

loadBalanced=true je třetí volba topologie, určená pro clustery za load balancerem, který mluví protokolem MongoDB (používají ho některé spravované serverless nabídky). Nelze ji kombinovat s replicaSet, directConnection=true ani s více než jedním hostem a uvidíš ji jen v URI, které ti dá poskytovatel.

Volby, které mění chování#

Úplný seznam voleb URI je dlouhý. Tohle jsou ty, které se objevují ve skutečných připojovacích řetězcích a mění, co klient dělá.

OptionDefaultEffect
authSourcepath db, else adminDatabáze, ve které je uživatel
tlsfalse; true for +srvŠifruje spojení
retryWritestrueJednou zopakuje neúspěšný zápis
wserver defaultPotvrzení zápisu
readPreferenceprimaryKteří členové obsluhují čtení
maxPoolSize100Spojení na server
connectTimeoutMSdriver-specificTimeout TCP spojení
appNamenoneŠtítek v logu serveru
directConnectionfalsePřeskočí zjišťování topologie

authSource

Určuje databázi, ve které byl uživatel vytvořen. Pravidla výchozích hodnot jsou výše a řešení problémů je v průvodci autentizací. Jediné, co sem přidat, je ekvivalent z příkazové řádky: mongosh přijímá --authenticationDatabase, což je totéž nastavení pod jiným názvem.

tls

tls=true šifruje spojení a ověřuje certifikát serveru proti systémovému úložišti důvěryhodných certifikátů, nebo proti CA uvedené v tlsCAFile. ssl=true je starší alias a pořád funguje. Server musí mít TLS nejdřív nakonfigurované; zapnutí v URI proti serveru, který ho nemá, selže při handshake a obvykle se projeví jako timeout. tlsAllowInvalidCertificates=true a tlsInsecure=true existují pro testování a nikdy by se neměly dostat do produkce.

retryWrites a w

retryWrites=true je v driverech výchozí od dob MongoDB 4.2. Zápis, který selže kvůli chybě sítě nebo volbě nového primary, se jednou bezpečně zopakuje, protože server sleduje identitu operace. Opakovatelné zápisy potřebují replica set nebo sharded cluster; na standalone serveru driver prostě neopakuje. Občas uvidíš retryWrites=false v řetězcích psaných pro staré servery nebo neobvyklé storage enginy - nech výchozí hodnotu, pokud ti chyba serveru neřekne něco jiného.

w nastavuje write concern: w=1 znamená, že zápis potvrdil primary, w=majority znamená, že ho potvrdila většina hlasujících členů, a w=0 znamená, že ho nepotvrdil nikdo a o selhání se nikdy nedozvíš. Od MongoDB 5.0 je implicitní výchozí hodnota serveru pro většinu replica setů majority, takže vynechat w z URI je obvykle správně. journal=true přidává „a je to na disku v žurnálu“ a wtimeoutMS brání tomu, aby zápis s majority čekal donekonečna, když je dostupných příliš málo členů. Na jediném serveru stačí na splnění majority ten samotný server.

readPreference

Přijímá primary, primaryPreferred, secondary, secondaryPreferred a nearest. Cokoli jiného než primary může vrátit data, která mírně zaostávají, protože secondaries replikují asynchronně. maxStalenessSeconds (minimum 90) vyloučí secondaries, které jsou příliš pozadu, a readPreferenceTags=dc:east nasměruje čtení na členy s odpovídajícími tagy. U jediného hostu nemá z čeho vybírat.

maxPoolSize a connectTimeoutMS

maxPoolSize platí na server a na klienta. Jeden klient mluvící s tříčlenným replica setem může při výchozí hodnotě otevřít až tři sta spojení a každý proces tvé aplikace má vlastního klienta. Nastav ho záměrně; connection pools and limits obsahuje výpočet. minPoolSize udržuje spojení připravená a maxIdleTimeMS zavírá nečinná.

connectTimeoutMS je timeout TCP připojení pro každé spojení a jeho výchozí hodnota je jednou z mála, které se mezi drivery liší: společná specifikace říká 10 sekund, PyMongo používá 20 a driver pro Node 30. Není to nastavení, kvůli kterému se špatné URI zasekne - to je serverSelectionTimeoutMS, všude 30 sekund. Novější drivery podporují také timeoutMS, jediný limit na straně klienta pro celou operaci, který má nahradit několik starších timeoutů pro jednotlivé fáze.

appName

Libovolný textový štítek do 128 bajtů, který se posílá v handshake spojení. Objeví se v logu serveru u každého spojení i v db.currentOp(), takže vidíš, která služba otevřela která spojení. Nestojí nic; nastav ho u každého klienta.

Sestavení URI pro běžná nasazení#

Většina řetězců spadá do několika málo tvarů. Přečíst si je vedle sebe jde rychleji než číst specifikaci.

code
# Local developmentmongodb://127.0.0.1:27017/shop# One remote server, user in adminmongodb://shopapp:pw@db.example.net:27017/shop?authSource=admin&appName=api# Three-member replica set, reads to secondaries allowedmongodb://shopapp:pw@db1.example.net,db2.example.net,db3.example.net/shop  ?replicaSet=rs0&authSource=admin&readPreference=secondaryPreferred# One member only, through an SSH tunnel on local port 27018mongodb://shopapp:pw@127.0.0.1:27018/shop?directConnection=true&authSource=admin# Managed cluster published in DNSmongodb+srv://shopapp:pw@cluster0.example.net/shop?appName=api# Same cluster written out by hand (what +srv was doing for you)mongodb://shopapp:pw@shard-00-00.example.net:27017,shard-00-01.example.net:27017  ,shard-00-02.example.net:27017/shop?replicaSet=rs0&authSource=admin&tls=true

Zalomení řádků v příkladech s replica setem slouží jen k čitelnosti; skutečné URI je jeden řádek bez mezer. Poslední příklad je ten, který si pamatuj, když je problém v DNS: převod +srv na prostý seznam znamená zkopírovat hosty ze záznamu SRV, volby ze záznamu TXT a přidat tls=true sám. Vynecháš-li kteroukoli ze tří věcí, spojení selže jiným způsobem.

Kam se řetězec zadává v jednotlivých klientech#

Každý oficiální driver přijímá stejné URI, což je smysl toho, že existuje. Liší se tím, odkud se řetězec čte a co co přebíjí.

PyMongo

python
import osfrom pymongo import MongoClientclient = MongoClient(os.environ["MONGODB_URI"], appName="reports", maxPoolSize=10)db = client.get_default_database()   # the /database from the URI

Pojmenované argumenty a volby URI jsou zaměnitelné a když se stejná volba objeví v obou, vyhrává pojmenovaný argument. get_default_database() vrací databázi z cesty a vyhodí chybu, pokud žádná není. Řetězec můžeš zkontrolovat bez připojení pomocí pymongo.uri_parser.parse_uri(uri), která vrátí zpracované hosty, přihlašovací údaje a volby jako slovník a vyhodí chybu u čehokoli poškozeného, včetně názvu +srv bez záznamů.

Driver pro Node.js

javascript
import { MongoClient } from "mongodb";const client = new MongoClient(process.env.MONGODB_URI, { appName: "api" });const db = client.db(); // the /database from the URI

Druhý argument přijímá stejné volby v camelCase. client.db() bez názvu vrací výchozí databázi z URI. Mongoose předá řetězec rovnou dál pomocí mongoose.connect(uri). Zpracování obstarává balíček mongodb-connection-string-url, na kterém driver závisí a který můžeš použít i sám, abys URI prohlédl nebo před zalogováním zamaskoval heslo.

mongosh

bash
$ mongosh 'mongodb://db1.example.net,db2.example.net/shop?replicaSet=rs0' \    -u shopapp -p --authenticationDatabase admin

URI dej do jednoduchých uvozovek, aby shell nechal na pokoji & a $. mongosh přijímá replica set také ve starší podobě --host rs0/db1.example.net:27017,db2.example.net:27017. Po připojení db.hello() ukáže setName, seznam členů a kdo je primary, což rozhodne jakoukoli pochybnost o tom, co driver objeví.

.NET: appsettings.json a web.config

Driver pro C# bere URI jako řetězec a v ASP.NET Core patří do sekce ConnectionStrings:

appsettings.json
{  "ConnectionStrings": {    "Mongo": "mongodb://shopapp:pw@db.example.net:27017/shop?authSource=admin"  }}
Program.cs
var cs = builder.Configuration.GetConnectionString("Mongo");var url = new MongoUrl(cs);builder.Services.AddSingleton<IMongoClient>(new MongoClient(url));builder.Services.AddSingleton(sp =>    sp.GetRequiredService<IMongoClient>().GetDatabase(url.DatabaseName));

MongoUrl řetězec zpracuje a jeho DatabaseName ti dá databázi z cesty. Klienta registruj jako singleton ze stejného důvodu jako u každého jiného driveru: je to pool. V produkci nastav hodnotu jako proměnnou prostředí ConnectionStrings__Mongo, místo abys heslo psal do souboru; vzor popisuje environment variables and secrets.

Na .NET Framework je řetězec ve web.config nebo app.config a čte se pomocí ConfigurationManager.ConnectionStrings["Mongo"].ConnectionString. Ten soubor je XML, takže každé & mezi volbami se musí psát jako &amp;:

web.config
<connectionStrings>  <add name="Mongo"       connectionString="mongodb://db.example.net:27017/shop?authSource=admin&amp;appName=legacy" /></connectionStrings>

Holé & tam způsobí, že se celý konfigurační soubor nenačte, což se obvykle hlásí jako chyba startu aplikace bez jakékoli zmínky o MongoDB. Stejnou myšlenku pro řetězce SQL Serveru najdeš v SQL Server connection strings.

Compass

Vlož URI do pole na obrazovce nového připojení. „Advanced Connection Options“ ho rozdělí do karet: karta General obsahuje přepínač schématu mezi mongodb a mongodb+srv, seznam hostů a zaškrtávátko Direct Connection; Authentication drží uživatelské jméno, heslo a autentizační databázi; TLS/SSL a Proxy/SSH mají vlastní karty. Úpravy v kartách přepisují řetězec a naopak, takže Compass je rozumný způsob, jak vidět, jak se vykládá URI, které ti někdo poslal - včetně toho, zda seznam hostů zpracoval tak, jak jsi myslel.

Chyby, které se týkají samotného formátu#

Tohle jsou chyby způsobené tvarem řetězce, ne přihlašovacími údaji nebo sítí.

  • Port v URI s `+srv`. mongodb+srv://cluster0.example.net:27017 se rovnou odmítne. Port odstraň.
  • Několik hostů v URI s `+srv`. Také se odmítne; +srv bere jeden název.
  • `directConnection=true` s více hosty. Odmítne se, protože není jediný server, ke kterému by se šlo připojit přímo.
  • Název `replicaSet`, který se neshoduje. Výběr serveru vyprší po 30 sekundách, přestože všechny hosty byly dosažitelné. Porovnej s db.hello().setName.
  • Myšlení v záložních serverech. Uvést v jednom URI produkční a záložní server nevytvoří failover mezi nesouvisejícími stroji. Pokud nejsou členy téhož replica setu, driver vidí dvě topologie, které si odporují, a dostaneš chyby, ne redundanci.
  • Mezery nebo zalomení řádků. Zkopírování zalomeného URI z dokumentu nebo zprávy v chatu přinese mezeru nebo nový řádek navíc. Drivery hlásí neplatný host nebo neznámou volbu a ten zbloudilý znak je ve většině logů neviditelný.
  • Nezakódované speciální znaky v hesle. Podrobně v MongoDB connection strings; ve zkratce zakóduj jednou, nebo předej přihlašovací údaje jako samostatné volby.

Na RE:NODE MongoDB hostingu se každý server vytvoří s přihlašovacími údaji vygenerovanými právě pro něj a připojuje se přímo na host a port uvedený u tarifu. Nepublikují se pro něj žádné záznamy SRV a před ním není žádná proxy, takže správná je forma mongodb:// s tímto hostem a portem, vygenerovaným uživatelem a authSource ukazujícím na databázi, ve které uživatel žije. Kde panel tyto údaje zobrazuje, ukazuje sekce o databázích v průvodcích. Pokud tvoje aplikace běží na některé z aplikačních řad, například Python, Node.js nebo C# / .NET, patří URI do proměnných prostředí toho serveru na kartě Startup, ne do kódu.

FAQ#

Jaké je výchozí MongoDB URI?

mongodb://localhost:27017, bez přihlašovacích údajů a bez databáze. Pokud se localhost na tvém stroji překládá na IPv6 a mongod poslouchá jen na IPv4, použij místo toho mongodb://127.0.0.1:27017.

Mohu použít mongodb+srv s IP adresou?

Ne. +srv existuje kvůli vyhledávání záznamů SRV a TXT pro DNS název a IP adresa žádné nemá. Použij mongodb:// s adresou a portem.

Musím v URI vypsat každého člena replica setu?

Ne. Stačí jeden dostupný člen, protože zbytek se driver dozví od setu. Uvedení dvou nebo tří znamená, že klient může nastartovat, i když je jeden z nich vypnutý, a proto to tak dělá většina produkčních řetězců.

Proč moje aplikace po upgradu driveru začala zapisovat na jiný server?

Nejspíš se změnila výchozí hodnota directConnection. Novější drivery zjišťují replica set z jediného hostu a posílají zápisy na primary. Přidej directConnection=true, pokud opravdu myslíš ten jeden server, a nech to vypnuté, pokud chceš běžné chování replica setu.

Záleží na pořadí voleb v URI?

Ne. Volby jsou množina dvojic klíč-hodnota. Záleží na tom, že volba v URI přebíjí stejnou volbu ze záznamu TXT u +srv a že argumenty driveru předané v kódu obvykle přebíjejí URI.

Co dělá replicaSet na jediném serveru?

Na standalone serveru způsobí selhání spojení, protože server nehlásí žádný název setu a driver čeká na člena rs0. Přidej replicaSet jen tehdy, když server opravdu je členem replica setu, byť jednočlenného.