<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex Bevilacqua</title>
    <description>The latest articles on DEV Community by Alex Bevilacqua (@alexbevi).</description>
    <link>https://dev.to/alexbevi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F604120%2F777958aa-501c-48bb-8cf0-46b9886dbd50.png</url>
      <title>DEV Community: Alex Bevilacqua</title>
      <link>https://dev.to/alexbevi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexbevi"/>
    <language>en</language>
    <item>
      <title>Cloudflare + MongoDB: How to fix 'Error: Dynamic require of "punycode/" is not supported'</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Wed, 31 Dec 2025 13:50:50 +0000</pubDate>
      <link>https://dev.to/alexbevi/cloudflare-mongodb-how-to-fix-error-dynamic-require-of-punycode-is-not-supported-1hmh</link>
      <guid>https://dev.to/alexbevi/cloudflare-mongodb-how-to-fix-error-dynamic-require-of-punycode-is-not-supported-1hmh</guid>
      <description>&lt;p&gt;If you've followed my &lt;a href="https://alexbevi.com/blog/2025/03/25/cloudflare-workers-and-mongodb/" rel="noopener noreferrer"&gt;previous post&lt;/a&gt; to try and connect to MongoDB from Cloudflare workers, it's possible you've come across the following issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Dynamic require of "punycode/" is not supported
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TL;DR is there is an issue with how &lt;code&gt;@cloudflare/vite-plugin&lt;/code&gt; is &lt;a href="https://github.com/jsdom/tr46/pull/73" rel="noopener noreferrer"&gt;processing an import with a trailing slash within the &lt;code&gt;tr46&lt;/code&gt; library&lt;/a&gt;, which is a transitive dependency of the MongoDB Node.js driver. The current solution is to patch this out until a proper fix is in place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reproduction
&lt;/h3&gt;

&lt;p&gt;Let's begin with a new application we can use as a minimum reproduction. Chances are you've already got an application ready that's hitting this issue, but if not we can verify this behavior by simply &lt;a href="https://developers.cloudflare.com/workers/framework-guides/web-apps/react-router/" rel="noopener noreferrer"&gt;creating a new React Router app using &lt;code&gt;create-cloudflare&lt;/code&gt;&lt;/a&gt; as follows, then adding the MongoDB Node.js driver as a dependency and importing it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# create a new react router app&lt;/span&gt;
npm create cloudflare@latest &lt;span class="nt"&gt;--&lt;/span&gt; my-react-router-app &lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;react-router
&lt;span class="nb"&gt;cd &lt;/span&gt;my-react-router-app
&lt;span class="c"&gt;# install mongodb&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;mongodb &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;span class="c"&gt;# prepend an import to the workers/app.ts file&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'import { MongoClient } from "mongodb";\n%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;workers/app.ts&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; workers/app.ts
&lt;span class="c"&gt;# update wrangler.jsonc with compatibility flags to support SSR&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'/"compatibility_date": "2025-04-04"/a\
  "compatibility_flags": ["nodejs_compat"],'&lt;/span&gt; wrangler.jsonc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a freshly bootstrapped application, let's try running it to see what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; dev
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; react-router dev

11:15:07 AM &lt;span class="o"&gt;[&lt;/span&gt;vite] &lt;span class="o"&gt;(&lt;/span&gt;ssr&lt;span class="o"&gt;)&lt;/span&gt; Re-optimizing dependencies because vite config has changed
11:15:08 AM &lt;span class="o"&gt;[&lt;/span&gt;vite] &lt;span class="o"&gt;(&lt;/span&gt;ssr&lt;span class="o"&gt;)&lt;/span&gt; ✨ new dependencies optimized: mongodb
11:15:08 AM &lt;span class="o"&gt;[&lt;/span&gt;vite] &lt;span class="o"&gt;(&lt;/span&gt;ssr&lt;span class="o"&gt;)&lt;/span&gt; ✨ optimized dependencies changed. reloading
&lt;span class="o"&gt;[&lt;/span&gt;vite] program reload
Error: Dynamic require of &lt;span class="s2"&gt;"punycode/"&lt;/span&gt; is not supported
    at null.&amp;lt;anonymous&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/.vite/deps_ssr/chunk-PLDDJCW6.js:11:9&lt;span class="o"&gt;)&lt;/span&gt;
    at node_modules/tr46/index.js &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/tr46/index.js:3:18&lt;span class="o"&gt;)&lt;/span&gt;
    at __require2 &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/.vite/deps_ssr/chunk-PLDDJCW6.js:17:50&lt;span class="o"&gt;)&lt;/span&gt;
    at node_modules/whatwg-url/lib/url-state-machine.js &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/whatwg-url/lib/url-state-machine.js:2:14&lt;span class="o"&gt;)&lt;/span&gt;
    at __require2 &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/.vite/deps_ssr/chunk-PLDDJCW6.js:17:50&lt;span class="o"&gt;)&lt;/span&gt;
    at node_modules/whatwg-url/lib/URL-impl.js &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/whatwg-url/lib/URL-impl.js:2:13&lt;span class="o"&gt;)&lt;/span&gt;
    at __require2 &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/.vite/deps_ssr/chunk-PLDDJCW6.js:17:50&lt;span class="o"&gt;)&lt;/span&gt;
    at node_modules/whatwg-url/lib/URL.js &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/whatwg-url/lib/URL.js:499:14&lt;span class="o"&gt;)&lt;/span&gt;
    at __require2 &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/.vite/deps_ssr/chunk-PLDDJCW6.js:17:50&lt;span class="o"&gt;)&lt;/span&gt;
    at node_modules/whatwg-url/webidl2js-wrapper.js &lt;span class="o"&gt;(&lt;/span&gt;/Users/alex/Temp/my-react-router-app/node_modules/whatwg-url/webidl2js-wrapper.js:3:13&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;cause]: undefined
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vite is complaining that the dynamic require of "punycode/" is not supported. The trailing slash following "punycode" is interesting, but we should first see where it's being imported. We can do this by using &lt;a href="https://docs.npmjs.com/cli/v7/commands/npm-ls" rel="noopener noreferrer"&gt;&lt;code&gt;npm ls&lt;/code&gt;&lt;/a&gt; to quickly narrow down usage of &lt;code&gt;punycode&lt;/code&gt; to the &lt;code&gt;tr46&lt;/code&gt; library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;ls &lt;/span&gt;punycode
my-react-router-app@ /Users/alex/Temp/my-react-router-app
└─┬ mongodb@7.0.0
  └─┬ mongodb-connection-string-url@7.0.0
    └─┬ whatwg-url@14.2.0
      └─┬ tr46@5.1.1
        └── punycode@2.3.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspecting the &lt;code&gt;tr46&lt;/code&gt; library at &lt;a href="https://github.com/jsdom/tr46/blob/main/index.js" rel="noopener noreferrer"&gt;https://github.com/jsdom/tr46/blob/main/index.js&lt;/a&gt; shows the trailing slash on the import as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;punycode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;punycode/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;--- this is the line in question&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;regexes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./lib/regexes.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mappingTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./lib/mappingTable.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;STATUS_MAPPING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./lib/statusMapping.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I initially tried to open a PR at &lt;a href="https://github.com/jsdom/tr46/pull/73" rel="noopener noreferrer"&gt;https://github.com/jsdom/tr46/pull/73&lt;/a&gt; to sort this out, but the maintainer points out that the issue is with Vite, so we'll need to look elsewhere for a solution. This change (introduced in commit &lt;a href="https://github.com/jsdom/tr46/commit/fef6e95243caaa0e46a1aa42fa21af6caef11e51" rel="noopener noreferrer"&gt;&lt;code&gt;fef6e95&lt;/code&gt;&lt;/a&gt;) was likely done to address &lt;code&gt;punycode&lt;/code&gt; deprecation warnings such as that described in &lt;a href="https://github.com/jsdom/tr46/issues/63" rel="noopener noreferrer"&gt;https://github.com/jsdom/tr46/issues/63&lt;/a&gt;. For more info on those deprecations see &lt;a href="https://medium.com/@asimabas96/solving-the-punycode-module-is-deprecated-issue-in-node-js-93437637948a" rel="noopener noreferrer"&gt;"Solving the \"Punycode Module is Deprecated\" Issue in Node.js"&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Patching
&lt;/h3&gt;

&lt;p&gt;We're going to solve this issue in a roundabout fashion using &lt;a href="https://www.npmjs.com/package/patch-package" rel="noopener noreferrer"&gt;&lt;code&gt;patch-package&lt;/code&gt;&lt;/a&gt; to modify the &lt;code&gt;punycode&lt;/code&gt; import directly in our &lt;code&gt;node_packages&lt;/code&gt; and then have a &lt;code&gt;postinstall&lt;/code&gt; script that will ensure the patch is consistently applied.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install patch-package&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;patch-package
&lt;span class="c"&gt;# update package.json to run patch-package as well as cf-typegen (which is there by default)&lt;/span&gt;
npm pkg &lt;span class="nb"&gt;set &lt;/span&gt;scripts.postinstall&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"patch-package &amp;amp;&amp;amp; npm run cf-typegen"&lt;/span&gt;
&lt;span class="c"&gt;# update node_modules/tr46/index.js to remove the trailing slash from the import&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'s/require("punycode\/")/require("punycode")/g'&lt;/span&gt; node_modules/tr46/index.js
&lt;span class="c"&gt;# create a patch for the tr46 package based on the above change&lt;/span&gt;
npx patch-package tr46
&lt;span class="c"&gt;# reinstall and apply patches&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should do it! When we run &lt;code&gt;npm install&lt;/code&gt; it will also run the &lt;code&gt;postinstall&lt;/code&gt;, which will apply the patch we just created.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Though patching transient dependencies to work around an issue like this is not ideal, it does offer a path forward for anyone hitting this specific error. To summarize what we did to address the issue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the &lt;code&gt;patch-package&lt;/code&gt; library (&lt;code&gt;npm install patch-package&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Update your &lt;code&gt;package.json&lt;/code&gt;'s &lt;code&gt;scripts.postinstall&lt;/code&gt; to prepend a &lt;code&gt;patch-package&lt;/code&gt; script to any &lt;code&gt;postinstall&lt;/code&gt; scripts that may already be present&lt;/li&gt;
&lt;li&gt;Modify &lt;code&gt;node_modules/tr46/index.js&lt;/code&gt; to remove the trailing &lt;code&gt;/&lt;/code&gt; from &lt;code&gt;require("punycode/")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create the patch by running &lt;code&gt;npx patch-package tr46&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ensure the patch is applied by running &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hopefully we can get this sorted out more cleanly (reported as &lt;a href="https://github.com/cloudflare/workers-sdk/issues/11751" rel="noopener noreferrer"&gt;https://github.com/cloudflare/workers-sdk/issues/11751&lt;/a&gt;), but in the meantime feel free to use this approach if you find it suitable.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>cloudflare</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>MongoDB Drivers and Network Compression</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Thu, 13 Nov 2025 16:19:50 +0000</pubDate>
      <link>https://dev.to/alexbevi/mongodb-drivers-and-network-compression-4b7</link>
      <guid>https://dev.to/alexbevi/mongodb-drivers-and-network-compression-4b7</guid>
      <description>&lt;p&gt;MongoDB's drivers communicate with a MongoDB process using the &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol" rel="noopener noreferrer"&gt;Wire Protocol&lt;/a&gt;, which is a simple socket-based, request-response style protocol that primarily uses the &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/#op_msg" rel="noopener noreferrer"&gt;&lt;code&gt;OP_MSG&lt;/code&gt;&lt;/a&gt; opcode (though &lt;a href="https://www.mongodb.com/docs/v6.0/release-notes/6.0-compatibility/#std-label-legacy-op-codes-removed" rel="noopener noreferrer"&gt;prior to MongoDB 6.0&lt;/a&gt; there were a number of additional &lt;a href="https://www.mongodb.com/docs/manual/legacy-opcodes" rel="noopener noreferrer"&gt;legacy opcodes&lt;/a&gt;). Since the contents of &lt;code&gt;OP_MSG&lt;/code&gt; messages was uncompressed, starting with MongoDB 3.4 a new opcode was introduced that would enable the Wire Protocol to support compressed messages as well: &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/#op_compressed" rel="noopener noreferrer"&gt;&lt;code&gt;OP_COMPRESSED&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All official &lt;a href="https://www.mongodb.com/docs/drivers/" rel="noopener noreferrer"&gt;MongoDB drivers&lt;/a&gt; allow you to enable and configure &lt;a href="https://www.mongodb.com/docs/manual/reference/connection-string-options/#compression-options" rel="noopener noreferrer"&gt;compression options&lt;/a&gt; via the connection string. To use any of the available compressors, they'd need to first be &lt;a href="https://www.mongodb.com/docs/manual/reference/configuration-options/#mongodb-setting-net.compression.compressors" rel="noopener noreferrer"&gt;enabled for each &lt;code&gt;mongod&lt;/code&gt; or &lt;code&gt;mongos&lt;/code&gt; instance through the &lt;code&gt;net.compression.compressors&lt;/code&gt; option&lt;/a&gt;, however all compressors are currently enabled by default, so you'd really only need to modify this to remove support for a given compressor.&lt;/p&gt;

&lt;p&gt;Enabling network compression for your workload is as easy as appending &lt;code&gt;compressors=xxx&lt;/code&gt; (where &lt;code&gt;xxx&lt;/code&gt; is one or more compressors as comma-separated values) to your connection string. For every &lt;code&gt;MongoClient&lt;/code&gt; created with this connection string, &lt;em&gt;almost all&lt;/em&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt; database commands will be compressed, which can result in massive reductions in the amount of data that needs to be sent back and forth to a MongoDB process.&lt;/p&gt;

&lt;p&gt;As a simple demonstration, I've instrumented a Node.js-based workload (see &lt;a href="https://github.com/alexbevi/node-tcp-metrics" rel="noopener noreferrer"&gt;alexbevi/node-tcp-metrics&lt;/a&gt;) to hook into &lt;a href="https://nodejs.org/api/net.html#netcreateconnection" rel="noopener noreferrer"&gt;&lt;code&gt;net.createConnection()&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://nodejs.org/api/net.html#class-netserver" rel="noopener noreferrer"&gt;&lt;code&gt;net.Server&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://nodejs.org/api/tls.html#tlsconnectoptions-callback" rel="noopener noreferrer"&gt;&lt;code&gt;tls.connect()&lt;/code&gt;&lt;/a&gt; to track the number of bytes being sent/received:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./tcp-metrics.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./tcp-metrics.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Chance&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MONGODB_URI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MONGODB_URI environment variable is not set&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;testdb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;testcollection&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Chance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Fixed seed for deterministic generation&lt;/span&gt;

    &lt;span class="c1"&gt;// Generate a complex document structure that's approximately 5MB&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Adjust to control size&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;itemCount&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;city&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;country&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;bio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paragraph&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;word&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
      &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;lastLogin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pickone&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;large-doc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;large-doc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Document insert and read complete, doc size (bytes):&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;large-doc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MongoDB error:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;socketSummary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When this is run, the workload will create a complex JSON document using &lt;a href="https://chancejs.com/" rel="noopener noreferrer"&gt;Chance&lt;/a&gt;, write it to a &lt;a href="https://www.mongodb.com/products/platform/atlas-database" rel="noopener noreferrer"&gt;MongoDB Atlas Database&lt;/a&gt;, then read it back before deleting it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ MONGODB_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mongodb+srv://USER:PASS@abc.cdefg.mongodb.net/"&lt;/span&gt; npm run dev

Document insert and &lt;span class="nb"&gt;read complete&lt;/span&gt;, doc size &lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;: 4725754
&lt;span class="o"&gt;{&lt;/span&gt; rx: 5058704, tx: 5058304, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1093, tx: 523, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.101:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1093, tx: 523, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.116:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1117, tx: 523, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;There are 4 open sockets in the example as the default Atlas configuration is a 3 member &lt;a href="https://www.mongodb.com/docs/manual/replication/" rel="noopener noreferrer"&gt;replica set&lt;/a&gt;. The driver has opened one socket to send commands to the server, and has also created dedicated monitoring connections to each host. If the workload were to remain active and not exit immediately, another 3 RTT connections would also be opened (one to each host in the replica set) for a total of 7 sockets. \&lt;br&gt;
See the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.md" rel="noopener noreferrer"&gt;Server Monitoring specification&lt;/a&gt;, or &lt;a href="https://dev.to%20post_url%202023-07-04-how-many-connections-is-my-application-establishing-to-my-mongodb-cluster%20"&gt;"How Many Connections is My Application Establishing to My MongoDB Cluster?"&lt;/a&gt; for more detail.&lt;br&gt;
{: .prompt-info }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;MongoDB supports 3 possible network compressors: &lt;a href="https://zlib.net/" rel="noopener noreferrer"&gt;zlib&lt;/a&gt;, ZStandard (&lt;a href="https://facebook.github.io/zstd/" rel="noopener noreferrer"&gt;zstd&lt;/a&gt;) and &lt;a href="https://google.github.io/snappy/" rel="noopener noreferrer"&gt;Snappy&lt;/a&gt;. zlib is always supported out of the box, however some drivers may require an additional package to support additional compressors. For example, when using MongoDB's &lt;a href="https://www.mongodb.com/docs/drivers/node/current/" rel="noopener noreferrer"&gt;Node.js driver&lt;/a&gt;, the following would be required from &lt;code&gt;npm&lt;/code&gt; to support snappy and zstd:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/snappy" rel="noopener noreferrer"&gt;&lt;code&gt;snappy&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@mongodb-js/zstd" rel="noopener noreferrer"&gt;&lt;code&gt;@mongodb-js/zstd&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our workload is using the default &lt;a href="https://www.mongodb.com/docs/manual/core/read-preference/" rel="noopener noreferrer"&gt;read preference&lt;/a&gt;, so with a baseline of &lt;code&gt;rx: 5058704, tx: 5058304&lt;/code&gt; being sent to and received from the &lt;a href="https://www.mongodb.com/docs/manual/core/replica-set-primary/" rel="noopener noreferrer"&gt;replica set primary&lt;/a&gt;, let's explore the impact of network compression.&lt;/p&gt;

&lt;h3&gt;
  
  
  zlib
&lt;/h3&gt;

&lt;p&gt;zlib is a software library used for data compression as well as a data format. zlib was written by Jean-loup Gailly and Mark Adler and implements the DEFLATE compression algorithm used in their gzip file compression program. The first public version of Zlib, 0.9, was released on 1 May 1995 and was originally intended for use with the libpng image library. It is free software, distributed under the zlib License.&lt;/p&gt;

&lt;p&gt;To test this compressor we append &lt;code&gt;compressors=zlib&lt;/code&gt; to our connection string and re-run our script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ MONGODB_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mongodb+srv://USER:PASS@abc.cdefg.mongodb.net/?compressors=zlib"&lt;/span&gt; npm run dev

Document insert and &lt;span class="nb"&gt;read complete&lt;/span&gt;, doc size &lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;: 4725754
&lt;span class="o"&gt;{&lt;/span&gt; rx: 2417301, tx: 2361623, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1147, tx: 515, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1123, tx: 518, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.101:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1123, tx: 518, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.116:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;zlib&lt;/code&gt; compression enabled we can see about a &lt;strong&gt;52% decrease&lt;/strong&gt; in the amount of data sent over the wire for this workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uncompressed:      rx: 5058704, tx: 5058304
compressed (zlib): rx: 2417301, tx: 2361623
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ZStandard (zstd)
&lt;/h3&gt;

&lt;p&gt;Zstandard is a lossless data compression algorithm developed by Yann Collet at Facebook. Zstd is the corresponding reference implementation in C, released as open-source software on 31 August 2016. The algorithm was published in 2018 as RFC 8478, which also defines an associated media type "application/zstd", filename extension "zst", and HTTP content encoding "zstd".&lt;/p&gt;

&lt;p&gt;To test this compressor we append &lt;code&gt;compressors=zstd&lt;/code&gt; to our connection string and re-run our script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ MONGODB_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mongodb+srv://USER:PASS@abc.cdefg.mongodb.net/?compressors=zstd"&lt;/span&gt; npm run dev

Document insert and &lt;span class="nb"&gt;read complete&lt;/span&gt;, doc size &lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;: 4725754
&lt;span class="o"&gt;{&lt;/span&gt; rx: 2395239, tx: 2394798, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1147, tx: 519, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1123, tx: 519, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.101:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1123, tx: 519, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.116:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;zstd&lt;/code&gt; compression enabled we can see about a &lt;strong&gt;53% decrease&lt;/strong&gt; in the amount of data sent over the wire for this workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uncompressed:      rx: 5058704, tx: 5058304
compressed (zstd): rx: 2395239, tx: 2394798
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Snappy
&lt;/h3&gt;

&lt;p&gt;Snappy (previously known as Zippy) is a fast data compression and decompression library written in C++ by Google based on ideas from LZ77 and open-sourced in 2011. It does not aim for maximum compression, or compatibility with any other compression library; instead, it aims for very high speeds and reasonable compression. Compression speed is 250 MB/s and decompression speed is 500 MB/s using a single core of a circa 2011 "Westmere" 2.26 GHz Core i7 processor running in 64-bit mode. The compression ratio is 20–100% lower than gzip.&lt;/p&gt;

&lt;p&gt;To test this compressor we append &lt;code&gt;compressors=snappy&lt;/code&gt; to our connection string and re-run our script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ MONGODB_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mongodb+srv://USER:PASS@abc.cdefg.mongodb.net/?compressors=snappy"&lt;/span&gt; npm run dev

Document insert and &lt;span class="nb"&gt;read complete&lt;/span&gt;, doc size &lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;: 4725754
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1125, tx: 527, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.116:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 3807095, tx: 3797837, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1149, tx: 527, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.108:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; rx: 1125, tx: 527, label: &lt;span class="s1"&gt;'xxx.yyy.zzz.101:27017'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;snappy&lt;/code&gt; compression enabled we can see about a &lt;strong&gt;25% decrease&lt;/strong&gt; in the amount of data sent over the wire for this workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uncompressed:        rx: 5058704, tx: 5058304
compressed (snappy): rx: 3807095, tx: 3797837
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Though there may be a need for an additional dependency, Zstandard compression is likely the best option as it will provide good compression with a low memory footprint. For Node.js specifically this requirement will likely go away once the driver's minimum runtime version rises to Node 24 as &lt;a href="https://nodejs.org/en/blog/release/v23.8.0#support-for-the-zstd-compression-algorithm" rel="noopener noreferrer"&gt;zstd support was added in 23.8.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're running your workload in AWS (or anywhere really), &lt;a href="https://aws.amazon.com/blogs/architecture/overview-of-data-transfer-costs-for-common-architectures/" rel="noopener noreferrer"&gt;data transfer costs&lt;/a&gt; will contribute to your overall costs. You can use tools like the &lt;a href="https://calculator.aws" rel="noopener noreferrer"&gt;AWS pricing calculator&lt;/a&gt; to dig into cost projections, but given you can potentially slash those in half (at least for the data going to/from your cluster) with a simple connection string update it makes MongoDB a more cost-effective option for your application.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;small&gt;Per the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/compression/OP_COMPRESSED.md#messages-not-allowed-to-be-compressed" rel="noopener noreferrer"&gt;Wire Compression specification&lt;/a&gt;, some commands should not be compressed. These include &lt;code&gt;hello&lt;/code&gt;/&lt;code&gt;ismaster&lt;/code&gt;, &lt;code&gt;saslStart&lt;/code&gt;, &lt;code&gt;saslContinue&lt;/code&gt;, &lt;code&gt;getnonce&lt;/code&gt;, &lt;code&gt;authenticate&lt;/code&gt;, &lt;code&gt;createUser&lt;/code&gt;, &lt;code&gt;updateUser&lt;/code&gt;, &lt;code&gt;copydbSaslStart&lt;/code&gt;, &lt;code&gt;copydbgetnonce&lt;/code&gt; and &lt;code&gt;copydb&lt;/code&gt;.&lt;/small&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>mongodb</category>
      <category>networking</category>
      <category>compression</category>
      <category>javascript</category>
    </item>
    <item>
      <title>MongoDB Driver Compatibility with MongoDB Servers</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Tue, 05 Aug 2025 09:52:39 +0000</pubDate>
      <link>https://dev.to/alexbevi/mongodb-driver-compatibility-with-mongodb-servers-4m11</link>
      <guid>https://dev.to/alexbevi/mongodb-driver-compatibility-with-mongodb-servers-4m11</guid>
      <description>&lt;p&gt;MongoDB server versions &lt;a href="https://www.mongodb.com/legal/support-policy/lifecycles" rel="noopener noreferrer"&gt;eventually reach EOL&lt;/a&gt; - as MongoDB 6.0 did on July 31, 2025. If your workload is running in MongoDB Atlas, the major version of your cluster will be automatically upgraded, but what if you haven't upgraded your application, its dependencies or the runtime environment? Will your application break? Is it still compatible? I wrote about this previously at &lt;a href="https://dev.to%20post_url%202023-01-13-will-upgrading-my-mongodb-server-version-break-my-application%20"&gt;&lt;em&gt;"Will Upgrading My MongoDB Server Version Break My Application?"&lt;/em&gt;&lt;/a&gt;, but there are still a lot of questions that pop up regarding driver compatibility so I wanted to go further.&lt;/p&gt;

&lt;p&gt;Though good dependency management hygiene is important, it's a time consuming process that can require extensive testing so you typically want to do it on your own terms - not because of a service upgrade.&lt;/p&gt;

&lt;p&gt;Let's assume your application uses &lt;a href="https://github.com/mongodb/node-mongodb-native/releases/tag/v4.17.2" rel="noopener noreferrer"&gt;v4.17.2&lt;/a&gt; of the MongoDB &lt;a href="https://mongodb-node.netlify.app/docs/drivers/node/current/" rel="noopener noreferrer"&gt;Node.js driver&lt;/a&gt;, but your application has been humming along for some time without issue. You got an email indicating your cluster was going to be upgraded from MongoDB 6.0 to MongoDB 7.0, but based on the &lt;a href="https://mongodb-node.netlify.app/docs/drivers/node/current/reference/compatibility/" rel="noopener noreferrer"&gt;driver compatibility table&lt;/a&gt; that version of the driver isn't even present!&lt;/p&gt;

&lt;h2&gt;
  
  
  What compatibility tables actually mean
&lt;/h2&gt;

&lt;p&gt;MongoDB drivers are constantly being updated to add support for new features of the MongoDB server, as well as address bugs/regressions and improve performance. The compatibility tables (such as the example below) are simply a reflection of what versions of the driver have previously had their test suite run against a version of the MongoDB server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbi1shqwkqcv42xbe1i6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbi1shqwkqcv42xbe1i6.png" alt="Node.js driver compatibility matrix"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The MongoDB drivers are all built from a set of &lt;a href="https://github.com/mongodb/specifications" rel="noopener noreferrer"&gt;common specifications&lt;/a&gt;, which are updated periodically as new MongoDB server features necessitate changes. For example, &lt;a href="https://www.mongodb.com/docs/manual/release-notes/7.0/#atlas-search-index-management" rel="noopener noreferrer"&gt;MongoDB 7.0 introduced Atlas Search Index Management&lt;/a&gt;, which resulted in the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/index-management/index-management.md" rel="noopener noreferrer"&gt;index management specifications&lt;/a&gt; being updated to define APIs drivers can implement to support the new database commands required to perform this new function.&lt;/p&gt;

&lt;p&gt;If the version of the driver being used doesn't contain support for MongoDB 7.0, new APIs such as &lt;a href="https://mongodb.github.io/node-mongodb-native/6.17/classes/Collection.html#createSearchIndex" rel="noopener noreferrer"&gt;&lt;code&gt;Collection#createSearchIndex&lt;/code&gt;&lt;/a&gt;wouldn't be directly available - but if you don't need this MongoDB 7.0 feature, your existing application using v4.17.2 of the Node.js driver would continue to function as expected.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since &lt;a href="https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/" rel="noopener noreferrer"&gt;&lt;code&gt;createSearchIndexes&lt;/code&gt;&lt;/a&gt;is a database command, even using a version of the driver that didn't have convenient APIs for interacting with the feature could still be used to &lt;a href="https://mongodb-node.netlify.app/docs/drivers/node/current/run-command/" rel="noopener noreferrer"&gt;run the database command directly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;


&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;commandDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;createSearchIndexes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contacts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;indexes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;searchIndex01&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mappings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;myDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commandDoc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What happens if I don't update my drivers
&lt;/h2&gt;

&lt;p&gt;The most likely outcome is - &lt;em&gt;nothing&lt;/em&gt;. Your application will continue to connect to your cluster, serialize and transmit database commands and receive and deserialize command responses. Even if the version of your driver is not present on the compatibility matrix, the &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/" rel="noopener noreferrer"&gt;MongoDB Wire Protocol&lt;/a&gt; the drivers use to communicate with your cluster hardly ever changes.&lt;/p&gt;

&lt;p&gt;As such, operationally your workload &lt;em&gt;should&lt;/em&gt; continue to function as expected. Since the MongoDB server version has changed the performance profile of your workload &lt;em&gt;may&lt;/em&gt; change, but this would not likely be a result of the driver remaining unchanged.&lt;/p&gt;

&lt;p&gt;Older drivers may not receive security updates or performance improvements - however this is true of your application's dependencies. Plan to update your driver, but rest assured that doing so should be compatible with your application or business' maintenance schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can my application actually break if I do nothing
&lt;/h2&gt;

&lt;p&gt;Yes - but for VERY specific reasons, all of which would be documented thoroughly and communicated prior to a major MongoDB server release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wire Protocol changes
&lt;/h3&gt;

&lt;p&gt;As mentioned previously, the wire protocol is extremely stable and rarely changes, however with the release of MongoDB 6.0, all &lt;a href="https://www.mongodb.com/docs/manual/release-notes/6.0-compatibility/#std-label-legacy-op-codes-removed" rel="noopener noreferrer"&gt;legacy opcodes were removed&lt;/a&gt;. This meant applications using drivers that had not been updated since MongoDB 3.4 (which reached EOL in 2020) would stop working as soon as their cluster was upgraded to 6.0.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;THIS IS THE ONLY WIRE PROTOCOL CHANGE OF THIS NATURE TO DATE&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Command removals
&lt;/h3&gt;

&lt;p&gt;On occasion, database commands may be replaced or removed. This will not happen prior to a deprecation period (at least one major release prior). This happened previously when &lt;a href="https://www.mongodb.com/docs/manual/release-notes/5.0-compatibility/#removed-commands" rel="noopener noreferrer"&gt;MongoDB 5.0 removed a number of deprecated commands&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If applications happen to be using those commands directly, once the MongoDB server is upgraded to a version that removes support for them, those applications would throw errors where those commands are used - such as the following example (using &lt;code&gt;mongosh&lt;/code&gt;, which is built using the Node.js driver):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mf"&gt;4.4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;resetError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;
&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;resetError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;MongoServerError&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CommandNotFound&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;such&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resetError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each major MongoDB server release will contain both release notes and compatibility changes. Make sure to review the compatibility changes to ensure if there are any command removals, they don't represent commands your application is using.&lt;/p&gt;

&lt;p&gt;See the following for reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/release-notes/8.0-compatibility/" rel="noopener noreferrer"&gt;MongoDB 8.0 Compatibility Changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/release-notes/7.0-compatibility/" rel="noopener noreferrer"&gt;MongoDB 7.0 Compatibility Changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/release-notes/6.0-compatibility/" rel="noopener noreferrer"&gt;MongoDB 6.0 Compatibility Changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/release-notes/5.0-compatibility/" rel="noopener noreferrer"&gt;MongoDB 5.0 Compatibility Changes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Not having a driver considered "compatible" doesn't mean the application won't continue to work&lt;/li&gt;
&lt;li&gt;Compatibility implies "feature compatibility" - as in "new" features of the server version listed&lt;/li&gt;
&lt;li&gt;Not upgrading your driver &lt;em&gt;shouldn't&lt;/em&gt; result in your application breaking&lt;/li&gt;
&lt;li&gt;There are scenarios where not upgrading the driver will break your application, but these are few, far between and well documented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are multiple benefits to keeping your application's dependencies up to date, but there can also be drawbacks. As such it's important to test upgrades in a lower environment to ensure as many potential issues can be caught prior to applying changes in production environments.&lt;/p&gt;

&lt;p&gt;If you're working with Node.js, consider tooling like &lt;a href="https://github.com/pilotpirxie/dependency-time-machine" rel="noopener noreferrer"&gt;&lt;code&gt;dependency-time-machine&lt;/code&gt;&lt;/a&gt; to help with sequential dependency update automation. Since your dependency graph is likely complex, this type of approach can help update your application incrementally in a way that may minimize interdependency compatibility issues.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Call Stack, But Make It Async!</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Fri, 12 Jul 2024 18:10:02 +0000</pubDate>
      <link>https://dev.to/alexbevi/call-stack-but-make-it-async-3g7i</link>
      <guid>https://dev.to/alexbevi/call-stack-but-make-it-async-3g7i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Written by &lt;a class="mentioned-user" href="https://dev.to/nbbeeken"&gt;@nbbeeken&lt;/a&gt; (&lt;a href="https://nbbeeken.github.io/" rel="noopener noreferrer"&gt;Blog&lt;/a&gt;, &lt;a href="https://github.com/nbbeeken" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In a recent release of the MongoDB Node.js driver (&lt;a href="https://github.com/mongodb/node-mongodb-native/releases/tag/v6.5.0" rel="noopener noreferrer"&gt;v6.5.0&lt;/a&gt;) the team completed the effort of getting all our asynchronous operations to report an accurate asynchronous stack trace to assist in pinpointing error origination. Here, I'll walk you through what this feature of JavaScript is and how to obtain it at the low price of zero-cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calls and how to stack them 📚
&lt;/h2&gt;

&lt;p&gt;First, what is a &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Call_stack" rel="noopener noreferrer"&gt;call stack&lt;/a&gt;? A call stack is a hidden data structure that stores information about the active subroutines of a program; active subroutines being functions that have been called but have yet to complete execution and return control to the caller. The main function of the call stack is to keep track of the point to which each active subroutine should return control when it finishes executing.&lt;/p&gt;

&lt;p&gt;Let's go through an example, take a program that parses a string from its arguments that is an equation like "2+2" and computes the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parseString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;splitString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;stringLength&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;stringToNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;printResult&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of us are familiar with the above procedural paradigm (whether from JavaScript, C, Java, or Python) where each step in the program is synchronous, so our call stack is a clear ordering of dependent procedures. For example, if &lt;code&gt;stringLength&lt;/code&gt; fails, the call stack would contain &lt;code&gt;stringLength&lt;/code&gt;, &lt;code&gt;splitString&lt;/code&gt;, &lt;code&gt;parseString&lt;/code&gt;, and &lt;code&gt;main&lt;/code&gt; as active procedures that have yet to return to their callers. The error system of our runtime uses this stack trace to generate a helpful error trace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;file://addNumbers.mjs:35
    throw new Error('cannot get string length')
          ^
Error: cannot get string length
    at stringLength (file://addNumbers.mjs:35:11)
    at splitString (file://addNumbers.mjs:17:17)
    at parseString (file://addNumbers.mjs:11:19)
    at main (file://addNumbers.mjs:4:5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Async wrench 🔧
&lt;/h3&gt;

&lt;p&gt;Everything changes when we shift to an asynchronous programming model, as the introduction of asynchronous work means we no longer have strictly dependent procedures. Essentially, async programming is about setting up tasks and adding handling that will be invoked some time later when the task is complete.&lt;/p&gt;

&lt;p&gt;Let's add I/O (a read from standard in) into our program to see how this changes our call stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;readStdin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleUserInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// When the user finishes typing&lt;/span&gt;
&lt;span class="nf"&gt;handleUserInput&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parseString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;splitString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;stringLength&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, main's only job is to ask the runtime to read from stdin and invoke a function of our choice when it is done doing so. This means main is no longer an active procedure; it returns leaving it up to the runtime to keep the process running until it has input from stdin to hand back to our function &lt;code&gt;handleUserInput&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's what the stack trace looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;file://addNumbers.mjs:42
    throw new Error('cannot get string length')
    ^
Error: cannot get string length
    at stringLength (file://addNumbers.mjs:42:11)
    at splitString (file://addNumbers.mjs:24:17)
    at parseString (file://addNumbers.mjs:18:19)
    at ReadStream.handleUserInput (file://addNumbers.mjs:11:5)
    at ReadStream.emit (node:events:511:28)
    at addChunk (node:internal/streams/readable:332:12)
    at readableAddChunk (node:internal/streams/readable:305:9)
    at Readable.push (node:internal/streams/readable:242:10)
    at TTY.onStreamRead (node:internal/stream_base_commons:190:23)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No sign of &lt;code&gt;main&lt;/code&gt;, only &lt;code&gt;handleUserInput&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a common hazard of asynchronous programming: you are always replacing the record of your active procedures as they are all performing task setup that completes and the callbacks they created are later invoked by the runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript 💚
&lt;/h2&gt;

&lt;p&gt;Asynchronous programming has always been at the heart of JS and is one of the central selling points of using Node.js.&lt;/p&gt;

&lt;p&gt;In 2015, the first &lt;a href="https://nodejs.org/en/blog/release/v4.2.0" rel="noopener noreferrer"&gt;Long Term Support version of Node.js was released&lt;/a&gt;, and with it came a stable standard library that popularized a common pattern for handling asynchronous tasks. All asynchronous tasks would accept a callback as their last argument, with the callback taking at least two arguments: an error, and the task's result. The pattern was that if the first argument was &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy" rel="noopener noreferrer"&gt;truthy&lt;/a&gt; (an error object) the task failed, and if it was not then the second argument would contain the result.&lt;/p&gt;

&lt;p&gt;Here's a simplified example of a function that reads a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;filename.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file contents&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Node.js callback pattern is ubiquitous and familiar, resulting in many popular libraries such as the &lt;a href="https://www.mongodb.com/docs/drivers/node/current/" rel="noopener noreferrer"&gt;MongoDB Node.js driver&lt;/a&gt; adopting it as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  No throw, only callback 🐕
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaxrqaigwfkds87osm4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaxrqaigwfkds87osm4s.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;image credit: &lt;a href="https://cupcakelogic.tumblr.com/post/124392369931/she-is-still-learning" rel="noopener noreferrer"&gt;cupcakelogic&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A challenge associated with the callback pattern is the requirement that the implementer keep in mind execution expectations manually, otherwise they can end up with a confusing order of operations.&lt;/p&gt;

&lt;p&gt;Typically this is something that should be abstracted to the runtime or language, which can be broken down as follows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Properly implementing the callback pattern means errors are passed as variables to a chain of handlers so they eventually reach the top-level initiator of the async operation. The syntax and keywords &lt;code&gt;throw&lt;/code&gt;/&lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; can no longer be used for control flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;filename&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ? */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// So what's the truth?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Runtime order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Callbacks also demand the developers ensure execution order is consistent. If a file is successfully read and the contents are returned in the callback passed to &lt;code&gt;readFile&lt;/code&gt;, that callback will always run after the code that is on the line following &lt;code&gt;readFile&lt;/code&gt;. However, say &lt;code&gt;readFile&lt;/code&gt; is passed an invalid argument, like a number instead of a string for the path. When it invokes the callback with an invalid argument error we would still expect that code to run in the same order as the success case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid argument&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="c1"&gt;// open &amp;amp; read file ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xF113&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cannot read file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contents:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;starting to read file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above prints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cannot read file Error: invalid argument
starting to read file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas when I change &lt;code&gt;readFile&lt;/code&gt; to be called with a non-existent path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;starting to read file
cannot read file Error: /notAPath.txt Does Not Exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is unexpected! The implementer of readFile calls the callback synchronously for an invalid type so readFile does not return until that callback completes. It is fairly easy to write callback accepting functions that inconsistently order their execution in this way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promises 🤞
&lt;/h3&gt;

&lt;p&gt;Introducing a more structured approach: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;Promises&lt;/a&gt;. A Promise is an object that handles the resolution or rejection of an async operation, mitigating the above issues and allowing for many async operations to be chained together without needing to explicitly pass a finalizer callback through to each API that would indicate when all tasks are done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// callbacks&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nx"&gt;client&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// promises&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;
 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({}))&lt;/span&gt;
 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note how in the promise code there is one error handling case as opposed to the two in the callback case. The ability to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#chaining" rel="noopener noreferrer"&gt;chain promises&lt;/a&gt; allows us to treat many async operations as one, the &lt;code&gt;catch&lt;/code&gt; handler would be called if either the &lt;code&gt;connect&lt;/code&gt; or the &lt;code&gt;find&lt;/code&gt; methods were to throw an error. This chaining is convenient, but when writing JavaScript today we do even better by using special syntax for handling promises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; 🔁
&lt;/h3&gt;

&lt;p&gt;Mid-2017 JavaScript engines shipped support for &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; syntax allowing programmers to write asynchronous operations in a familiar procedural format. Using &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; allows the programmer to encode their logical asynchronous dependencies right into the syntax of the language.&lt;/p&gt;

&lt;p&gt;Let's return to our user input example, as we can now "await" the input which keeps &lt;code&gt;main&lt;/code&gt; as the active procedure that began the task to read from standard in.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"For &lt;code&gt;await&lt;/code&gt; the suspend and resume points coincide and so we not only know where we would continue, but by coincidence, we also know where we came from."&lt;/p&gt;

&lt;p&gt;source: &lt;a href="https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit#heading=h.e6lcalo0cl47" rel="noopener noreferrer"&gt;Zero-cost async stack traces&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When the input is available, &lt;code&gt;readStdin&lt;/code&gt; will resolve and we can continue with our parsing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readStdin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parseString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;file://addNumbers.mjs:43
    throw new Error('cannot get string length')
          ^
Error: cannot get string length
    at stringLength (file://addNumbers.mjs:43:11)
    at splitString (file://addNumbers.mjs:25:17)
    at parseString (file://addNumbers.mjs:19:19)
    at main (file://addNumbers.mjs:9:5)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async file://addNumbers.mjs:62:1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the JavaScript engine reaches the "await", &lt;code&gt;main&lt;/code&gt; is suspended. The engine is free to handle other tasks while the read is waiting for our user to type. We can now encode into the syntax of the function that it will suspend until some other task completes, and when it continues it maintains the context of everything that was in scope when it started.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;"The fundamental difference between &lt;code&gt;await&lt;/code&gt; and manually constructed promises is that &lt;code&gt;await X()&lt;/code&gt; &lt;strong&gt;suspends&lt;/strong&gt; execution of the current function, while &lt;code&gt;promise.then(X)&lt;/code&gt; will &lt;strong&gt;continue&lt;/strong&gt; execution of the current function after adding the &lt;code&gt;X&lt;/code&gt; call to the callback chain. In the context of stack traces, this difference is pretty significant."&lt;/p&gt;

&lt;p&gt;source: &lt;a href="https://mathiasbynens.be/notes/async-stack-traces" rel="noopener noreferrer"&gt;Why await beats Promise#then() · Mathias Bynens&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Sample Stack Traces
&lt;/h2&gt;

&lt;p&gt;Prior to completing the &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; conversion down to the internal network layer of the driver, our error stack would begin at the point of converting a server's error message into a JavaScript, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MongoServerError: Failing command via 'failCommand' failpoint
    at Connection.onMessage (./mongodb/lib/cmap/connection.js:231:30)
    at MessageStream.&amp;lt;anonymous&amp;gt; (./mongodb/lib/cmap/connection.js:61:60)
    at MessageStream.emit (node:events:520:28)
    at processIncomingData (./mongodb/lib/cmap/message_stream.js:125:16)
    at MessageStream._write (./mongodb/lib/cmap/message_stream.js:33:9)
    at writeOrBuffer (node:internal/streams/writable:564:12)
    at _write (node:internal/streams/writable:493:10)
    at Writable.write (node:internal/streams/writable:502:10)
    at Socket.ondata (node:internal/streams/readable:1007:22)
    at Socket.emit (node:events:520:28)
                    ^-- Sadness, that's not my code...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, post v6.5.0, the stack trace points directly back to the origination of an operation (we see you &lt;code&gt;main.js&lt;/code&gt;!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MongoServerError: Failing command via 'failCommand' failpoint
    at Connection.sendCommand (./mongodb/lib/cmap/connection.js:290:27)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Connection.command (./mongodb/lib/cmap/connection.js:313:26)
    at async Server.command (./mongodb/lib/sdam/server.js:167:29)
    at async FindOperation.execute (./mongodb/lib/operations/find.js:34:16)
    at async tryOperation (./mongodb/lib/operations/execute_operation.js:192:20)
    at async executeOperation (./mongodb/lib/operations/execute_operation.js:69:16)
    at async FindCursor._initialize (./mongodb/lib/cursor/find_cursor.js:51:26)
    at async FindCursor.cursorInit (./mongodb/lib/cursor/abstract_cursor.js:471:27)
    at async FindCursor.fetchBatch (./mongodb/lib/cursor/abstract_cursor.js:503:13)
    at async FindCursor.next (./mongodb/lib/cursor/abstract_cursor.js:228:13)
    at async Collection.findOne (./mongodb/lib/collection.js:274:21)
    at async main (./mongodb/main.js:19:3)
                   ^-- Yay, that's my code!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Additional Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit" rel="noopener noreferrer"&gt;Zero-cost async stack traces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tc39/proposal-error-stacks" rel="noopener noreferrer"&gt;tc39/proposal-error-stacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://v8.dev/docs/stack-trace-api" rel="noopener noreferrer"&gt;Stack trace API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://v8.dev/blog/modern-javascript#proper-tail-calls" rel="noopener noreferrer"&gt;ES2015, ES2016, and beyond · Tail Calls · V8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://v8.dev/blog/fast-async" rel="noopener noreferrer"&gt;Faster async functions and promises · V8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mathiasbynens.be/notes/async-stack-traces" rel="noopener noreferrer"&gt;Asynchronous stack traces: why await beats Promise#then() · Mathias Bynens&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Peeling the MongoDB Drivers Onion</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Tue, 21 May 2024 18:59:35 +0000</pubDate>
      <link>https://dev.to/alexbevi/peeling-the-mongodb-drivers-onion-2gma</link>
      <guid>https://dev.to/alexbevi/peeling-the-mongodb-drivers-onion-2gma</guid>
      <description>&lt;p&gt;The modern MongoDB driver consists of a number of components, each of which are thoroughly documented in the &lt;a href="https://github.com/mongodb/specifications"&gt;Specifications&lt;/a&gt; repository. Though this information is readily available and extremely helpful, what it lacks is a high level overview to tie the specs together into a cohesive picture of what a MongoDB driver is.&lt;/p&gt;

&lt;p&gt;Architecturally an implicit hierarchy exists within the drivers, so expressing drivers in terms of an &lt;a href="https://en.wikipedia.org/wiki/Onion_model"&gt;onion model&lt;/a&gt; feels appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layers of the Onion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7cfa2qi7021e90nedmnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7cfa2qi7021e90nedmnn.png" alt="Image description" width="786" height="836"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;"drivers onion"&lt;/em&gt; is meant to represent how various concepts, components and APIs can be layered atop each other to build a MongoDB driver from the ground up, or to help understand how existing drivers have been structured. Hopefully this representation of MongoDB’s drivers helps provide some clarity, as the complexity of these libraries - like the onion above - could otherwise bring you to tears.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serialization
&lt;/h3&gt;

&lt;p&gt;At their lowest level all MongoDB drivers will need to know how to work with &lt;a href="https://bsonspec.org/"&gt;BSON&lt;/a&gt;. BSON (short for "Binary JSON") is a bin­ary-en­coded serialization of &lt;a href="https://www.json.org/json-en.html"&gt;JSON&lt;/a&gt;-like documents, and like JSON, it sup­ports the nesting of arrays and documents. BSON also contains extensions that al­low representation of data types that are not part of the &lt;a href="https://datatracker.ietf.org/doc/html/rfc7159"&gt;JSON spec&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; &lt;a href="https://bsonspec.org/spec.html"&gt;BSON&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/objectid.rst"&gt;ObjectId&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.md"&gt;Decimal128&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/uuid.rst"&gt;UUID&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/dbref.md"&gt;DBRef&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/extended-json.rst"&gt;Extended JSON&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Communication
&lt;/h3&gt;

&lt;p&gt;Once BSON documents can be created and manipulated, the foundation for interacting with a MongoDB host process has been laid. Drivers communicate by sending &lt;a href="https://www.mongodb.com/docs/manual/reference/command/"&gt;database commands&lt;/a&gt; as serialized BSON documents using MongoDB’s &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/"&gt;wire protocol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From the provided connection string and options a socket connection is established to a host, which an initial handshake verifies is in fact a valid MongoDB connection by sending a simple &lt;a href="https://www.mongodb.com/docs/manual/reference/command/hello/"&gt;&lt;code&gt;hello&lt;/code&gt;&lt;/a&gt;. Based on the response to this first command a driver can continue to establish and authenticate connections.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; &lt;a href="https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.md"&gt;&lt;code&gt;OP_MSG&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/run-command/run-command.rst"&gt;Command Execution&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/connection-string/connection-string-spec.md"&gt;Connection String&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.md"&gt;URI Options&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/ocsp-support/ocsp-support.rst"&gt;OCSP&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst"&gt;Initial Handshake&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/compression/OP_COMPRESSED.md"&gt;Wire Compression&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/socks5-support/socks5.rst"&gt;SOCKS5&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.md"&gt;Initial DNS Seedlist Discovery&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Connectivity
&lt;/h3&gt;

&lt;p&gt;Now that a valid host has been found, the cluster’s topology can be discovered and monitoring connections can be established. Connection pools can then be created and populated with connections. The monitoring connections will subsequently be used for ensuring operations are routed to available hosts, or hosts that meet certain criteria (such as a configured &lt;a href="https://www.mongodb.com/docs/upcoming/core/read-preference/"&gt;read preference&lt;/a&gt; or acceptable latency window).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst"&gt;SDAM&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.md"&gt;CMAP&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/load-balancers/load-balancers.md"&gt;Load Balancer Support&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;Establishing and monitoring connections to MongoDB ensures they’re available, but MongoDB server processes typically will require the connection to be &lt;a href="https://www.mongodb.com/docs/manual/core/authentication/"&gt;authenticated&lt;/a&gt; before commands will be accepted. MongoDB offers many authentication mechanisms such as &lt;a href="https://www.mongodb.com/docs/manual/core/security-scram"&gt;SCRAM&lt;/a&gt;, &lt;a href="https://www.mongodb.com/docs/manual/core/security-x.509/"&gt;x.509&lt;/a&gt;, &lt;a href="https://www.mongodb.com/docs/manual/core/kerberos/"&gt;Kerberos&lt;/a&gt;, &lt;a href="https://www.mongodb.com/docs/manual/core/security-ldap/"&gt;LDAP&lt;/a&gt;, &lt;a href="https://www.mongodb.com/docs/manual/core/security-oidc/"&gt;OpenID Connect&lt;/a&gt; and &lt;a href="https://www.mongodb.com/docs/atlas/security/passwordless-authentication/"&gt;AWS IAM&lt;/a&gt;, which MongoDB drivers support using the &lt;em&gt;&lt;a href="https://www.ietf.org/rfc/rfc4422.txt"&gt;Simple Authentication and Security Layer&lt;/a&gt;&lt;/em&gt; (SASL) framework.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; &lt;a href="https://github.com/mongodb/specifications/blob/master/source/auth/auth.md"&gt;Authentication&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Availability
&lt;/h3&gt;

&lt;p&gt;All client operations will be serialized as BSON and sent to MongoDB over a connection that will first be checked out of a connection pool. Various monitoring processes exist to ensure a driver’s internal state machine contains an accurate view of the cluster’s topology so that read and write requests can always be appropriately routed according to MongoDB’s &lt;a href="https://www.mongodb.com/docs/manual/core/read-preference-mechanics/"&gt;server selection algorithm&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.md"&gt;Server Monitoring&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/polling-srv-records-for-mongos-discovery/polling-srv-records-for-mongos-discovery.rst"&gt;&lt;code&gt;SRV&lt;/code&gt; Polling for mongos Discovery&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.md"&gt;Server Selection&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/max-staleness/max-staleness.md"&gt;Max Staleness&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Resilience
&lt;/h3&gt;

&lt;p&gt;At their core, database drivers are client libraries meant to facilitate interactions between an application and the database. MongoDB’s drivers are no different in that regard, as they abstract away the underlying serialization, communication, connectivity, and availability functions required to programmatically interact with your data.&lt;/p&gt;

&lt;p&gt;To further enhance the developer experience while working with MongoDB, various resilience features can be added based on &lt;a href="https://www.mongodb.com/docs/manual/reference/server-sessions/"&gt;logical sessions&lt;/a&gt; such as &lt;a href="https://www.mongodb.com/docs/manual/core/retryable-writes"&gt;retryable writes&lt;/a&gt;, &lt;a href="https://www.mongodb.com/docs/manual/core/read-isolation-consistency-recency/#std-label-causal-consistency"&gt;causal consistency&lt;/a&gt;, and &lt;a href="https://www.mongodb.com/docs/manual/core/transactions/"&gt;transactions&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; Retryability (&lt;a href="https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.md"&gt;Reads&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.md"&gt;Writes&lt;/a&gt;), &lt;a href="https://github.com/mongodb/specifications/blob/master/source/client-side-operations-timeout/client-side-operations-timeout.md"&gt;CSOT&lt;/a&gt;, Consistency (&lt;a href="https://github.com/mongodb/specifications/blob/master/source/sessions/driver-sessions.md"&gt;Sessions&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.md"&gt;Causal Consistency&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/sessions/snapshot-sessions.md"&gt;Snapshot Reads&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/transactions/transactions.md"&gt;Transactions&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/transactions-convenient-api/transactions-convenient-api.rst"&gt;Convenient Transactions API&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Programmability
&lt;/h3&gt;

&lt;p&gt;Now that we can serialize commands and send them over the wire through an authenticated connection we can begin actually manipulating data. Since all database interactions are in the form of commands, if we wanted to remove a single document we might issue a &lt;a href="https://www.mongodb.com/docs/manual/reference/command/delete"&gt;&lt;code&gt;delete&lt;/code&gt; command&lt;/a&gt; such as the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;deletes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Though not exceedingly complex, a better developer experience can be achieved through more single-purpose APIs. This would allow the above example to be expressed as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To provide a cleaner and clearer developer experience, many specifications exist to describe how these APIs should be consistently presented across driver implementations, while still providing the flexibility to make APIs more idiomatic for each language.&lt;/p&gt;

&lt;p&gt;Advanced security features such as &lt;a href="https://www.mongodb.com/docs/manual/core/csfle/"&gt;client-side field level encryption&lt;/a&gt; are also defined at this layer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; Resource Management (&lt;a href="https://github.com/mongodb/specifications/blob/master/source/enumerate-databases.rst"&gt;Databases&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/enumerate-collections.rst"&gt;Collections&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/index-management/index-management.md"&gt;Indexes&lt;/a&gt;), Data Management (&lt;a href="https://github.com/mongodb/specifications/blob/master/source/crud/crud.md"&gt;CRUD&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/collation/collation.md"&gt;Collation&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server_write_commands.rst"&gt;Write Commands&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/driver-bulk-update.rst"&gt;Bulk API&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/crud/bulk-write.md"&gt;Bulk Write&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/read-write-concern/read-write-concern.rst"&gt;R/W Concern&lt;/a&gt;), Cursors (&lt;a href="https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md"&gt;Change Streams&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/find_getmore_killcursors_commands.rst"&gt;&lt;code&gt;find&lt;/code&gt;/&lt;code&gt;getMore&lt;/code&gt;/&lt;code&gt;killCursors&lt;/code&gt;&lt;/a&gt;), &lt;a href="https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.md"&gt;GridFS&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/versioned-api/versioned-api.rst"&gt;Stable API&lt;/a&gt;, Security (&lt;a href="https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.md"&gt;Client Side Encryption&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/subtype6.md"&gt;BSON Binary Subtype 6&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Observability
&lt;/h3&gt;

&lt;p&gt;With database commands being serialized and sent to MongoDB servers and responses being received and deserialized, our driver can be considered fully functional for most read and write operations. As MongoDB drivers abstract away most of the complexity involved with creating and maintaining the connections these commands will be sent over, providing mechanisms for introspection into a driver’s functionality can provide developers with added confidence that things are working as expected.&lt;/p&gt;

&lt;p&gt;The inner workings of connection pools, connection lifecycle, server monitoring, topology changes, command execution and other driver components are exposed by means of events developers can register listeners to capture. This can be an invaluable troubleshooting tool and can help facilitate monitoring the health of an application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;BSON&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EJSON&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;EJSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongodb://localhost:27017&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monitorCommands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;commandStarted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;commandStarted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connectionCheckedOut&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connectionCheckedOut&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;coll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given the example above (using the &lt;a href="https://www.mongodb.com/docs/drivers/node/current/"&gt;Node.js driver&lt;/a&gt;) the specified connection events and command events would be logged as they’re emitted by the driver:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;connectionCheckedOut: {"time":{"$date":"2024-05-17T15:18:18.589Z"},"address":"localhost:27018","name":"connectionCheckedOut","connectionId":1}&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;commandStarted: {"name":"commandStarted","address":"127.0.0.1:27018","connectionId":1,"serviceId":null,"requestId":5,"databaseName":"test","commandName":"find","command":{"find":"foo","filter":{},"limit":1,"singleBatch":true,"batchSize":1,"lsid":{"id":{"$binary":{"base64":"4B1kOPCGRUe/641MKhGT4Q==","subType":"04"}}},"$clusterTime":{"clusterTime":{"$timestamp":{"t":1715959097,"i":1}},"signature":{"hash":{"$binary":"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"00"}},"keyId":0}},"$db":"test"},"serverConnectionId":140}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The preferred method of observing internal behavior would be through &lt;a href="https://github.com/mongodb/specifications/blob/master/source/logging/logging.md"&gt;standardized logging&lt;/a&gt; once it is available in all drivers (&lt;a href="https://jira.mongodb.org/browse/DRIVERS-1204"&gt;DRIVERS-1204&lt;/a&gt;), however until that time only event logging is consistently available. In the future additional observability tooling such as &lt;a href="https://opentelemetry.io/"&gt;Open Telemetry&lt;/a&gt; support may also be introduced.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; &lt;a href="https://github.com/mongodb/specifications/blob/master/source/command-logging-and-monitoring/command-logging-and-monitoring.rst"&gt;Command Logging and Monitoring&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring-logging-and-monitoring.md"&gt;SDAM Logging and Monitoring&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/logging/logging.md"&gt;Standardized Logging&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.md#connection-pool-logging"&gt;Connection Pool Logging&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Testability
&lt;/h3&gt;

&lt;p&gt;Ensuring existing as well as net-new drivers can be effectively tested for correctness and performance, most specifications define a standard set of tests using &lt;a href="https://web.archive.org/web/20230930061614/https://www.mongodb.com/blog/post/cat-herds-crook-yaml-test-specs-improve-driver-conformance"&gt;YAML tests to improve driver conformance&lt;/a&gt;. This allows specification authors and maintainers to describe functionality once with the confidence that the tests can be executed alike by language-specific test runners across all drivers.&lt;/p&gt;

&lt;p&gt;Though the unified test format greatly simplifies language-specific implementations, not all tests can be represented in this fashion. In those cases the specifications may describe tests to be manually implemented as prose. By limiting the number of prose tests that each driver must implement, engineers can deliver functionality with greater confidence while also minimizing the burden of upstream verification.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Specifications:&lt;/strong&gt; &lt;a href="https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.md"&gt;Unified Test Format&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/tree/master/source/atlas-data-lake-testing/tests"&gt;Atlas Data Federation Testing&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.md"&gt;Performance Benchmarking&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/bson-corpus/bson-corpus.md"&gt;BSON Corpus&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests"&gt;Replication Event Resilience&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/faas-automated-testing/faas-automated-testing.md"&gt;FAAS Automated Testing&lt;/a&gt;, &lt;a href="https://github.com/mongodb/specifications/blob/master/source/serverless-testing/README.rst"&gt;Atlas Serverless Testing&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Most (if not all) the information required to build a new driver or maintain existing drivers technically exists within the specifications, however without a mental mode of their composition and architecture it can be extremely challenging to know where to look.&lt;/p&gt;

&lt;p&gt;Peeling the &lt;em&gt;"drivers onion"&lt;/em&gt; should hopefully make reasoning about them a little easier, especially with the understanding that everything can be tested to validate individual implementations are "up to spec".&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>drivers</category>
      <category>architecture</category>
      <category>javascript</category>
    </item>
    <item>
      <title>MongoDB and Load Balancer Support</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Fri, 15 Mar 2024 01:53:45 +0000</pubDate>
      <link>https://dev.to/alexbevi/mongodb-and-load-balancer-support-1p28</link>
      <guid>https://dev.to/alexbevi/mongodb-and-load-balancer-support-1p28</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;A load balancer enhances your application's scalability, availability, and performance by efficiently distributing traffic across multiple servers based on a number of &lt;a href="https://kemptechnologies.com/load-balancer/load-balancing-algorithms-techniques"&gt;algorithms and techniques&lt;/a&gt; - but what about your database? MongoDB is a distributed database, but can it be placed behind a load balancer?&lt;/p&gt;

&lt;p&gt;Astute readers of MongoDB's Node.js driver's &lt;a href="https://github.com/mongodb/node-mongodb-native/tree/main/test#load-balanced"&gt;&lt;code&gt;test&lt;/code&gt; README&lt;/a&gt; may have noticed at some point that there is mention of a testing methodology for load balancers, and &lt;a href="https://www.mongodb.com/community/forums/t/load-balancing-mongos/247301"&gt;as some in the community have found&lt;/a&gt; you can find &lt;a href="https://jira.mongodb.org/browse/SERVER-58502"&gt;public &lt;code&gt;SERVER&lt;/code&gt; tickets&lt;/a&gt; that also allude to this functionality existing.&lt;/p&gt;

&lt;p&gt;Digging further you'll find the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/load-balancers/load-balancers.rst"&gt;&lt;em&gt;Load Balancer Support&lt;/em&gt;&lt;/a&gt; specification for MongoDB's drivers which states &lt;em&gt;"To specify to the driver to operate in load balancing mode, a connection string option of &lt;code&gt;loadBalanced=true&lt;/code&gt; MUST be added to the connection string"&lt;/em&gt; ... but how do you actually make that work?&lt;/p&gt;

&lt;p&gt;In this post we're going to explore why MongoDB nodes couldn't previously be placed behind an &lt;a href="https://www.nginx.com/resources/glossary/layer-4-load-balancing/"&gt;L4 load balancer&lt;/a&gt;, and what changed in MongoDB 5.3 that may actually make this possible!&lt;/p&gt;

&lt;h3&gt;
  
  
  Replication
&lt;/h3&gt;

&lt;p&gt;Coordination of data distribution and ensuring high availability is done via &lt;a href="https://www.mongodb.com/docs/manual/replication/"&gt;replication&lt;/a&gt;, which requires the cluster to be aware at all times which node is the &lt;a href="https://www.mongodb.com/docs/manual/core/replica-set-members/#primary"&gt;primary&lt;/a&gt; and which are &lt;a href="https://www.mongodb.com/docs/manual/core/replica-set-members/#secondaries"&gt;secondaries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As there can only be one primary, any application targeting the cluster will need to be aware of the current topology as well, as trying to write to a secondary will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mongo'&lt;/span&gt;
&lt;span class="c1"&gt;# connect directly to a secondary host in a local replica set&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Mongo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mongodb://localhost:27018/test?directConnection=true'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:foo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_one&lt;/span&gt; &lt;span class="ss"&gt;bar: &lt;/span&gt;&lt;span class="s2"&gt;"baz"&lt;/span&gt;

&lt;span class="c1"&gt;# =&amp;gt; Mongo::Error::OperationFailure: [10107:NotWritablePrimary]: not primary (on localhost:27018, legacy retry, attempt 1)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All official MongoDB drivers implement the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst"&gt;&lt;em&gt;Server Discovery and Monitoring&lt;/em&gt;&lt;/a&gt; specification to ensure applications can route requests to the appropriate servers (as outlined in the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.md"&gt;&lt;em&gt;Server Selection&lt;/em&gt;&lt;/a&gt; specification). When you have a single application instance with a single connection pool (as outlined in the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.md"&gt;&lt;em&gt;Connection Monitoring and Pooling&lt;/em&gt;&lt;/a&gt; specification) the number of connections to the cluster is easy to identify, but application deployment configurations can vary and scale.&lt;/p&gt;

&lt;p&gt;Thanks to MongoDB drivers all consistently providing connection monitoring and pooling functionality, external connection pooling solutions aren't required (ex: &lt;a href="https://www.pgpool.net/mediawiki/index.php/Main_Page"&gt;Pgpool&lt;/a&gt;, &lt;a href="https://www.pgbouncer.org/"&gt;PgBouncer&lt;/a&gt;). This allows applications built using MongoDB drivers to be resilient and scalable out of the box, but based on what we understand regarding &lt;a href="https://alexbevi.com/blog/2023/07/04/how-many-connections-is-my-application-establishing-to-my-mongodb-cluster/"&gt;the number of connections applications establish to MongoDB clusters&lt;/a&gt; it stands to reason that at a certain point as our application deployments increase, so will our connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use a load balancer though?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Due to the need for these additional monitoring connections it has been difficult (impossible?) to place a load balancer between applications and a MongoDB replica set - though adventurous users have developed &lt;a href="https://blog.danman.eu/mongodb-haproxy/"&gt;some interesting HAProxy configurations&lt;/a&gt; in the past to try and solve this problem. The problem you'd face is that though read requests can be routed to any available server, write requests &lt;em&gt;must&lt;/em&gt; target the cluster primary.&lt;/p&gt;

&lt;p&gt;For the sake of argument you may ask &lt;em&gt;"what if I had a 100% read workload?"&lt;/em&gt;. In that case you &lt;em&gt;could&lt;/em&gt; put your hosts behind a load balancer, but you'll likely run into issues as soon as you try and iterate a cursor (see &lt;a href="https://www.mongodb.com/docs/manual/reference/command/getMore/"&gt;&lt;code&gt;getMore&lt;/code&gt;&lt;/a&gt;). Operations such as &lt;a href="https://www.mongodb.com/docs/manual/reference/command/find/"&gt;&lt;code&gt;find&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://www.mongodb.com/docs/manual/reference/command/aggregate/"&gt;&lt;code&gt;aggregate&lt;/code&gt;&lt;/a&gt; return a cursor (&lt;code&gt;cursorId&lt;/code&gt;) which only exists on the originating server the command targeted. Attempting to execute a &lt;code&gt;getMore&lt;/code&gt; on the wrong server will result in a &lt;code&gt;CursorNotFound&lt;/code&gt; error being returned, which can be &lt;a href="https://alexbevi.com/blog/2021/12/29/troubleshooting-mongodb-cursor-xxxxxx-not-found-errors/"&gt;challenging to troubleshoot&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharding
&lt;/h3&gt;

&lt;p&gt;Fortunately, MongoDB already offers a form of "load balancing" for &lt;a href="https://www.mongodb.com/docs/manual/sharding/#sharded-cluster"&gt;sharded clusters&lt;/a&gt; in the form of the &lt;a href="https://www.mongodb.com/docs/manual/core/sharded-cluster-query-router/"&gt;sharded cluster query router&lt;/a&gt; (&lt;code&gt;mongos&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Assuming the cluster is sharded and if there is more than one &lt;code&gt;mongos&lt;/code&gt; instance in the &lt;a href="https://www.mongodb.com/docs/manual/reference/glossary/#std-term-seed-list"&gt;connection seed list&lt;/a&gt;, the driver determines which &lt;code&gt;mongos&lt;/code&gt; is the "closest" (i.e. the member with the lowest average network round-trip-time) and calculates the latency window by adding the average round-trip-time of this "closest" &lt;code&gt;mongos&lt;/code&gt; instance and the &lt;code&gt;localThresholdMS&lt;/code&gt;. The driver will load balance randomly across the &lt;code&gt;mongos&lt;/code&gt; instances that fall within the latency window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use a load balancer though?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sharding introduces a routing layer between the application and the cluster members, which slightly simplifies how drivers route operations as there is no longer a need to track replica set state. You may think this would make placing a pool of &lt;code&gt;mongos&lt;/code&gt;' behind a load balancer straightforward, but as Craig Wilson describes in a &lt;a href="http://craiggwilson.com/2013/10/21/load-balanced-mongos/"&gt;2013 blog post&lt;/a&gt;, similar issues will still arise when trying to iterate cursors. Note that though Craig's post references the &lt;a href="https://www.mongodb.com/docs/manual/legacy-opcodes/"&gt;legacy opcodes&lt;/a&gt;, the situation would be the same if using newer drivers that leverage &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/#std-label-wire-op-msg"&gt;&lt;code&gt;OP_MSG&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/#std-label-wire-op-compressed"&gt;&lt;code&gt;OP_COMPRESSED&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that the &lt;em&gt;Server Selection&lt;/em&gt; specification &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.md#cursors"&gt;calls out that&lt;/a&gt; &lt;em&gt;"Cursor operations [...] do not go through the server selection process. Cursor operations must be sent to the original server that received the query [...]"&lt;/em&gt;. As this state information would not be tracked within the load balancer, issues would arise if a cursor operation were attempted and a balancer returned a different server where the cursor didn't exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;operationCount&lt;/code&gt;-based Server Selection
&lt;/h3&gt;

&lt;p&gt;As it is a form of "load balancing" it's worth just calling out that in an effort to alleviate runaway connection creation scenarios ("connection storms") the drivers &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.md#operationcount-based-selection-within-the-latency-window-multi-threaded-or-async"&gt;approximate an individual server's load&lt;/a&gt; by tracking the number of concurrent operations that node is processing (&lt;code&gt;operationCount&lt;/code&gt;) and then routing operations to servers with less load. This should reduce the number of new operations routed towards nodes that are busier and thus increase the number routed towards nodes that are servicing operations faster or are simply less busy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancer Support
&lt;/h2&gt;

&lt;p&gt;When you see a ticket called &lt;a href="https://jira.mongodb.org/browse/SERVER-58207"&gt;"Enable Feature flag for Support for Deploying MongoDB behind a L4 Load Balancer"&lt;/a&gt; closed out as fixed for MongoDB&lt;br&gt;
6.0.0-rc0 and 5.3.0-rc3 it's hard not to get excited - but what does this mean? After doing a bit of digging you'll find that &lt;code&gt;mongos&lt;/code&gt;' now support a proxy protocol which is configured via the &lt;a href="https://github.com/mongodb/mongo/blob/r7.0.6/src/mongo/s/mongos_server_parameters.idl#L66-L74"&gt;&lt;code&gt;loadBalancerPort&lt;/code&gt;&lt;/a&gt; startup parameter.&lt;/p&gt;

&lt;p&gt;Given that there's a driver specification, driver implementations (such as for the &lt;a href="https://jira.mongodb.org/browse/NODE-3011"&gt;Node.js driver&lt;/a&gt; and &lt;a href="https://jira.mongodb.org/browse/RUBY-2515"&gt;Ruby driver&lt;/a&gt;) and server support it should be possible to configure a sharded cluster to utilize the proxy protocol.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before we proceed it's worth calling out that this is not considered an officially supported configuration. Until MongoDB's server team promotes this as a valid production configuration it should be considered experimental if used with a self-managed deployment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;For our test we'll be configuring a single-shard sharded cluster with 5 &lt;code&gt;mongos&lt;/code&gt;' behind an &lt;a href="https://www.haproxy.org/"&gt;HAProxy&lt;/a&gt; load balancer. Assuming you're already familiar with &lt;a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts"&gt;HAProxy and load balancing concepts&lt;/a&gt;, we'll be setting up a &lt;a href="https://www.haproxy.com/documentation/haproxy-configuration-tutorials/load-balancing/tcp/#enable-tcp-mode"&gt;TCP proxy&lt;/a&gt; to perform &lt;code&gt;roundrobin&lt;/code&gt; balancing.&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Setup a local sharded cluster
&lt;/h4&gt;

&lt;p&gt;First we need a local sharded cluster, which we'll provision using &lt;a href="https://github.com/aheckmann/m"&gt;&lt;code&gt;m&lt;/code&gt; - the MongoDB version manager&lt;/a&gt; and &lt;a href="https://github.com/rueckstiess/mtools"&gt;&lt;code&gt;mtools&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;m 7.0.6-ent
mlaunch init &lt;span class="nt"&gt;--replicaset&lt;/span&gt; &lt;span class="nt"&gt;--nodes&lt;/span&gt; 3 &lt;span class="nt"&gt;--shards&lt;/span&gt; 1 &lt;span class="nt"&gt;--csrs&lt;/span&gt; &lt;span class="nt"&gt;--mongos&lt;/span&gt; 5 &lt;span class="nt"&gt;--binarypath&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;m bin 7.0.6-ent&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--bind_ip_all&lt;/span&gt;
mlaunch stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration will yield a single &lt;a href="https://www.mongodb.com/docs/manual/core/sharded-cluster-shards/"&gt;shard&lt;/a&gt; with 3 nodes, a &lt;a href="https://www.mongodb.com/docs/manual/core/sharded-cluster-config-servers/#replica-set-config-servers"&gt;config server replica set&lt;/a&gt; and 5 &lt;code&gt;mongos&lt;/code&gt;'. Once started, we immediately stop the cluster as some additional (manual) configuration is required.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Update the cluster configuration to enable proxy protocol
&lt;/h4&gt;

&lt;p&gt;Since we need to modify the startup parameters for our &lt;code&gt;mongos&lt;/code&gt;' we'll update the configuration file that &lt;code&gt;mlaunch&lt;/code&gt; (part of &lt;code&gt;mtools&lt;/code&gt;) uses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'s/ --port 27017 / --port 27017 --setParameter loadBalancerPort=37017 /g'&lt;/span&gt; data/.mlaunch_startup
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'s/ --port 27018 / --port 27018 --setParameter loadBalancerPort=37018 /g'&lt;/span&gt; data/.mlaunch_startup
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'s/ --port 27019 / --port 27019 --setParameter loadBalancerPort=37019 /g'&lt;/span&gt; data/.mlaunch_startup
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'s/ --port 27020 / --port 27020 --setParameter loadBalancerPort=37020 /g'&lt;/span&gt; data/.mlaunch_startup
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="s1"&gt;'s/ --port 27021 / --port 27021 --setParameter loadBalancerPort=37021 /g'&lt;/span&gt; data/.mlaunch_startup
mlaunch start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above commands just append a &lt;a href="https://www.mongodb.com/docs/manual/reference/command/setParameter/"&gt;&lt;code&gt;setParameter&lt;/code&gt;&lt;/a&gt; call as a command line option so we can configure the &lt;code&gt;loadBalancerPort&lt;/code&gt; parameter of each &lt;code&gt;mongos&lt;/code&gt;. Once completed we restart the cluster.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Configure HAproxy
&lt;/h4&gt;

&lt;p&gt;As we're using HAproxy for our test we'll to build out our custom configuration. The example below will write to a &lt;code&gt;mongodb-lb.conf&lt;/code&gt; file, which will then be read by &lt;code&gt;haproxy&lt;/code&gt; to create our load balanced endpoint. I'm not going to go into detail as to what all the options below mean, but if you want to investigate further see &lt;a href="https://www.haproxy.com/documentation/haproxy-configuration-manual/latest/"&gt;HAproxy's configuration manual&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tee &lt;/span&gt;mongodb-lb.conf &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOT&lt;/span&gt;&lt;span class="sh"&gt;
global
  log stdout local0 debug
  maxconn 4096

defaults
  log global
  mode tcp
  timeout connect  5000ms
  timeout client  30000ms
  timeout server  30000ms
  retries 3

default-server on-error fastinter error-limit 3 inter 3000ms fastinter 1000ms downinter 300s fall 3

frontend stats
    mode http
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 10s
    stats admin if LOCALHOST

listen mongos
  bind      *:37000
  option    tcplog
  balance   roundrobin
  server    mongos01 *:37017 check send-proxy-v2
  server    mongos02 *:37018 check send-proxy-v2
  server    mongos03 *:37019 check send-proxy-v2
  server    mongos04 *:37020 check send-proxy-v2
  server    mongos05 *:37021 check send-proxy-v2
&lt;/span&gt;&lt;span class="no"&gt;EOT

&lt;/span&gt;haproxy &lt;span class="nt"&gt;-f&lt;/span&gt; mongodb-lb.conf &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; haproxy.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make monitoring a little easier you'll notice we've enabled &lt;a href="https://www.haproxy.com/blog/exploring-the-haproxy-stats-page"&gt;HAProxy's stats frontend&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Test application connectivity through the load balancer
&lt;/h4&gt;

&lt;p&gt;Since the &lt;a href="https://www.mongodb.com/docs/mongodb-shell/"&gt;MongoDB Shell&lt;/a&gt; uses the &lt;a href="https://www.mongodb.com/docs/drivers/node/current/"&gt;Node.js driver&lt;/a&gt; internally we can use to validate if our load balancer is configured properly. We've setup HAProxy to listen on port 37000, so we should be able to connect to that directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="s2"&gt;"mongodb://localhost:37000/test"&lt;/span&gt;
MongoServerSelectionError: The server is being accessed through a load balancer, but this driver does not have load balancing enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seems the driver knows we're trying to connect to a load balancer, but we're missing an option. This is where the &lt;code&gt;loadBalanced=true&lt;/code&gt; option comes into play. Appending this to our connection string will allow us to run an arbitrary workload successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="s2"&gt;"mongodb://localhost:37000/test?loadBalanced=true"&lt;/span&gt; &lt;span class="nt"&gt;--eval&lt;/span&gt; &lt;span class="s2"&gt;"while(true) { result = db.foo.insertOne({ d: new Date() }); print(result); sleep(500); }"&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  acknowledged: &lt;span class="nb"&gt;true&lt;/span&gt;,
  insertedId: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'65eb13b122c34af3037c094d'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  acknowledged: &lt;span class="nb"&gt;true&lt;/span&gt;,
  insertedId: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'65eb13b222c34af3037c094e'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  acknowledged: &lt;span class="nb"&gt;true&lt;/span&gt;,
  insertedId: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'65eb13b222c34af3037c094f'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success! It is worth noting though that this configuration works for us locally as we have direct control of the &lt;code&gt;mongos&lt;/code&gt; processes startup parameters.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have a MongoDB Atlas sharded cluster, the &lt;code&gt;mongos&lt;/code&gt;' cannot manually be placed behind a load balancer as startup parameter configuration access is not available!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now that we can successfully connect to our load balanced endpoint it's worth doing a little chaos testing to see how workloads react. The script I shared previously just loops infinitely inserting documents into a collection - but what happens if we kill one or two &lt;code&gt;mongos&lt;/code&gt; processes?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mlaunch stop 27017
mlaunch stop 27019
mlaunch list
Detected mongod version: 7.0.6

PROCESS          PORT     STATUS     PID

mongos           27017    down       -
mongos           27018    running    28006
mongos           27019    down       -
mongos           27020    running    28013
mongos           27021    running    28016

config server    27025    running    27979

shard01
    mongod       27022    running    27994
    mongod       27023    running    27998
    mongod       27024    running    27991
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;mlaunch&lt;/code&gt; I just stopped two of the query routers and waited for a while. The inserts kept on - inserting - so I guess we can consider that a successful test. Note that this is obviously not extensive and should not be taken as a guarantee of any sort, but if this is a configuration that interests you give it a shot and let me know what you find.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6teromsut55razz0gty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6teromsut55razz0gty.png" alt="Image description" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't forget that you have a web-based stats UI configured that you can refer to 😉.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>networking</category>
      <category>performance</category>
      <category>database</category>
    </item>
    <item>
      <title>Understanding client library and database preferences for JS/TS developers</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Tue, 12 Mar 2024 20:08:04 +0000</pubDate>
      <link>https://dev.to/alexbevi/understanding-client-library-and-database-preferences-for-jsts-developers-j9o</link>
      <guid>https://dev.to/alexbevi/understanding-client-library-and-database-preferences-for-jsts-developers-j9o</guid>
      <description>&lt;p&gt;I'm a Product Manager focusing on Developer Interfaces and am looking to better understand what client libraries and databases JavaScript/TypeScript developers currently prefer. If you're a JavaScript/TypeScript developer and have 5 minutes to spare I'd love to hear from you!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSd02AdPauVVWpzeObBgr0UoQ9MlxMCHRrTKhTQX5oLn5CDDiw/viewform?usp=pp_url&amp;amp;entry.237887320=Dev.to"&gt;Click here for the survey&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since everyone's time is valuable, if you complete this survey your email address will be entered into a draw to win a $50 Amazon gift card!&lt;/p&gt;

&lt;p&gt;I'll have the survey open until March 22nd, 2024. Once the results are processed I'll share my findings here in case others find it useful.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>survey</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Node.js Driver failing to connect due to "unsafe legacy renegotiation disabled"</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Tue, 05 Mar 2024 12:54:32 +0000</pubDate>
      <link>https://dev.to/alexbevi/nodejs-driver-failing-to-connect-due-to-unsafe-legacy-renegotiation-disabled-34ca</link>
      <guid>https://dev.to/alexbevi/nodejs-driver-failing-to-connect-due-to-unsafe-legacy-renegotiation-disabled-34ca</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://www.mongodb.com/community/forums/t/mongoserverselectionerror-c83200000a000152-ssl-routinesunsafe-legacy-renegotiation-disabled/262568"&gt;this community forum post&lt;/a&gt; there was a report of the &lt;a href="https://www.mongodb.com/docs/drivers/node/current/"&gt;MongoDB Node.js driver&lt;/a&gt; failing to connect with the following error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;MongoServerSelectionError: C8320000:error:0A000152:SSL routines:final_renegotiate:unsafe legacy renegotiation disabled:c:\ws\deps\openssl\openssl\ssl\statem\extensions.c:922&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This error doesn't smell like a MongoDB-specific error, so digging into &lt;em&gt;"&lt;code&gt;final_renegotiate:unsafe legacy renegotiation disabled&lt;/code&gt;"&lt;/em&gt; specifically lead to &lt;a href="https://github.com/openssl/openssl/issues/21296"&gt;this &lt;code&gt;openssl&lt;/code&gt; issue&lt;/a&gt; that looks to elaborate on the meaning of the error message:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TLSv1.2 (and earlier) support the concept of renegotiation. In 2009 (i.e. after the TLSv1.2 RFC was published), a flaw was discovered with how renegotiation works that could lead to an attack. After the attack was discovered a fix was deployed to all TLS libraries. In order for the fixed version of renegotiation to work both the client and the server need to support it.&lt;/p&gt;

&lt;p&gt;The original (unfixed) version of renegotiation is known as "unsafe legacy renegotiation" in OpenSSL. The fixed version is known as "secure renegotiation". So either a peer does not have the fix, in which case it will be using &lt;em&gt;"unsafe legacy renegotiation"&lt;/em&gt;, or it does have the fix in which case it will be using &lt;em&gt;"secure renegotiation"&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So it seems that the error originated from OpenSSL, and "that flaw" they're alluding to was likely &lt;a href="https://nvd.nist.gov/vuln/detail/cve-2009-3555"&gt;CVE-2009-3555&lt;/a&gt;. What was particularly interesting about this issue is that it &lt;em&gt;only&lt;/em&gt; occurred when the application was run using Node.js 20, while Node.js 16 didn't exhibit any issues - so what's different between those two versions? One notable change is that &lt;a href="https://nodejs.org/en/blog/vulnerability/openssl-november-2022"&gt;Node.js 17+ use OpenSSL 3.0 by default&lt;/a&gt; - and starting with 3.0 &lt;a href="https://github.com/openssl/openssl/pull/15127"&gt;secure negotiation support is required by default&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more information on secure server-side renegotiation I'd highly recommend &lt;a href="https://github.com/openssl/openssl/discussions/21747"&gt;this discussion&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring OpenSSL via the Node.js Driver
&lt;/h2&gt;

&lt;p&gt;A similar issue was reported on Stack Overflow for the &lt;a href="https://www.npmjs.com/package/axios"&gt;&lt;code&gt;axios&lt;/code&gt; library&lt;/a&gt;, and the &lt;a href="https://stackoverflow.com/a/74600467/195509"&gt;solution&lt;/a&gt; there was to pass &lt;code&gt;secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT&lt;/code&gt; during request creation. As &lt;code&gt;secureOptions&lt;/code&gt; is an option passed to Node's &lt;a href="https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions"&gt;&lt;code&gt;tls.createSecureContext&lt;/code&gt;&lt;/a&gt; API (which MongoDB &lt;a href="https://www.mongodb.com/docs/drivers/node/current/fundamentals/connection/tls/#securecontext-example"&gt;documents an example of using&lt;/a&gt;) it should be possible to do something similar with the Node.js driver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongodb+srv://...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;secureContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;secureOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SSL_OP_LEGACY_SERVER_CONNECT&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SUCCESS! The above example allows a &lt;code&gt;SecureContext&lt;/code&gt; object to be created with the &lt;code&gt;secureOptions&lt;/code&gt; selected from the &lt;a href="https://nodejs.org/api/crypto.html#openssl-options"&gt;enumerated OpenSSL options Node.js has defined&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Though the Node.js driver allows direct configuration of the &lt;code&gt;SecureContext&lt;/code&gt; object, as other &lt;a href="https://www.mongodb.com/docs/drivers/"&gt;MongoDB drivers&lt;/a&gt; &lt;em&gt;may not&lt;/em&gt;, &lt;a href="https://jira.mongodb.org/browse/DRIVERS-2823"&gt;DRIVERS-2823&lt;/a&gt; is being considered to ensure this type of configuration is available.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Alternative Configuration
&lt;/h2&gt;

&lt;p&gt;Configuring the MongoDB Node.js driver's OpenSSL options directly is likely the preferred approach, but the Node runtime can also be configured (via &lt;a href="https://nodejs.org/api/cli.html#--openssl-configfile"&gt;&lt;code&gt;--openssl-config=file&lt;/code&gt;&lt;/a&gt;). In this, when the &lt;code&gt;node&lt;/code&gt; process is executed the path to a custom OpenSSL configuration file could be provided as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--openssl-config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/to/openssl.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;openssl.conf&lt;/code&gt; is setup similar to the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nodejs_conf = openssl_init

[openssl_init]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
Options = UnsafeLegacyRenegotiation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>mongodb</category>
      <category>node</category>
      <category>ssl</category>
    </item>
    <item>
      <title>querySrv errors when connecting to MongoDB Atlas</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Thu, 29 Feb 2024 15:16:46 +0000</pubDate>
      <link>https://dev.to/alexbevi/querysrv-errors-when-connecting-to-mongodb-atlas-434j</link>
      <guid>https://dev.to/alexbevi/querysrv-errors-when-connecting-to-mongodb-atlas-434j</guid>
      <description>&lt;p&gt;If your application uses MongoDB's &lt;a href="https://www.mongodb.com/docs/drivers/node/current/"&gt;Node.js driver&lt;/a&gt; or &lt;a href="https://mongoosejs.com/"&gt;Mongoose ODM&lt;/a&gt;, occasionally you may observe errors such as &lt;code&gt;querySrv ECONNREFUSED _mongodb._tcp.cluster0.abcde.mongodb.net&lt;/code&gt; or &lt;code&gt;Error: querySrv ETIMEOUT _mongodb._tcp.cluster0.abcde.mongodb.net&lt;/code&gt; being thrown. The MongoDB Atlas documentation outlines several methods to &lt;a href="https://www.mongodb.com/docs/atlas/troubleshoot-connection/"&gt;troubleshoot connection issues&lt;/a&gt;, including how to handle &lt;a href="https://www.mongodb.com/docs/atlas/troubleshoot-connection/#connection-refused-using-srv-connection-string"&gt;"Connection Refused using SRV Connection String"&lt;/a&gt; scenarios, but why does this happen in the first place?&lt;/p&gt;

&lt;h2&gt;
  
  
  About DNS seedlists
&lt;/h2&gt;

&lt;p&gt;To coincide with the release of MongoDB 3.6, all drivers (at the time) implemented the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.rst"&gt;initial DNS seedlist discovery&lt;/a&gt; specification to ensure connections could be established using the new &lt;a href="https://www.mongodb.com/docs/manual/reference/connection-string/#std-label-connections-dns-seedlist"&gt;&lt;code&gt;SRV&lt;/code&gt; connection string format&lt;/a&gt;, as well as the legacy &lt;a href="https://www.mongodb.com/docs/manual/reference/connection-string/#standard-connection-string-format"&gt;standard connection string format&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This functionality was introduced to abstract away the complexity of MongoDB's connection strings (for MongoDB Atlas users at least) by moving the component parts of a &lt;a href="https://www.mongodb.com/docs/manual/reference/connection-string/"&gt;connection string&lt;/a&gt; to two DNS records: a &lt;a href="https://en.wikipedia.org/wiki/SRV_record"&gt;service record (&lt;code&gt;SRV&lt;/code&gt;)&lt;/a&gt; and a &lt;a href="https://en.wikipedia.org/wiki/TXT_record"&gt;text record (&lt;code&gt;TXT&lt;/code&gt;)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Users now only need to supply a connection string such as &lt;code&gt;mongodb+srv://&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@cluster0.abcde.mongodb.net/myFirstDatabase&lt;/code&gt;, and regardless as to whether the underlying cluster was a replica set or sharded, the connection string would remain the same. Furthermore, use of &lt;code&gt;mongodb+srv://&lt;/code&gt; enables drivers to detect additions/removals of &lt;code&gt;mongos&lt;/code&gt; in a sharded cluster&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Tools such as &lt;a href="https://linux.die.net/man/1/nslookup"&gt;&lt;code&gt;nslookup&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://linux.die.net/man/1/dig"&gt;&lt;code&gt;dig&lt;/code&gt;&lt;/a&gt; can be used to view the contents of these DNS records, such as in the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dig srv _mongodb._tcp.cluster0.abcde.mongodb.net

&lt;span class="p"&gt;;&lt;/span&gt; &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu &amp;lt;&amp;lt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; srv _mongodb._tcp.cluster0.abcde.mongodb.net
&lt;span class="p"&gt;;;&lt;/span&gt; global options: +cmd
&lt;span class="p"&gt;;;&lt;/span&gt; Got answer:
&lt;span class="p"&gt;;;&lt;/span&gt; -&amp;gt;&amp;gt;HEADER&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;opcode&lt;/span&gt;&lt;span class="sh"&gt;: QUERY, status: NOERROR, id: 24529
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;_mongodb._tcp.cluster0.abcde.mongodb.net. IN SRV

;; ANSWER SECTION:
_mongodb._tcp.cluster0.abcde.mongodb.net. 60 IN SRV 0 0 27017 cluster0-shard-00-01.abcde.mongodb.net.
_mongodb._tcp.cluster0.abcde.mongodb.net. 60 IN SRV 0 0 27017 cluster0-shard-00-02.abcde.mongodb.net.
_mongodb._tcp.cluster0.abcde.mongodb.net. 60 IN SRV 0 0 27017 cluster0-shard-00-00.abcde.mongodb.net.

&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="sh"&gt;dig txt cluster0.abcde.mongodb.net

; &amp;lt;&amp;lt;&amp;gt;&amp;gt; DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu &amp;lt;&amp;lt;&amp;gt;&amp;gt; txt cluster0.abcde.mongodb.net
;; global options: +cmd
;; Got answer:
;; -&amp;gt;&amp;gt;HEADER&amp;lt;&amp;lt;- opcode: QUERY, status: NOERROR, id: 35223
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;cluster0.abcde.mongodb.net.    IN  TXT

;; ANSWER SECTION:
cluster0.abcde.mongodb.net. 60 IN   TXT "authSource=admin&amp;amp;replicaSet=atlas-abcde-shard-0"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What can go wrong?
&lt;/h2&gt;

&lt;p&gt;MongoDB's drivers require the information from &lt;em&gt;both&lt;/em&gt; DNS queries in order to successfully establish, authenticate and authorize a connection to a MongoDB Atlas cluster. If either of these queries fail, only part of the connection string details will be present, and if the driver doesn't error out right away, the subsequent connection attempt may be missing necessary information.&lt;/p&gt;

&lt;p&gt;For example, per the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst#implementation"&gt;Authentication specification&lt;/a&gt; regarding connection string options, when it comes to selecting the authentication source:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;if &lt;a href="https://www.mongodb.com/docs/manual/reference/connection-string/#mongodb-urioption-urioption.authSource"&gt;&lt;code&gt;authSource&lt;/code&gt;&lt;/a&gt; is specified, it is used.&lt;/li&gt;
&lt;li&gt;otherwise, if database is specified (in the connection string), it is used.&lt;/li&gt;
&lt;li&gt;otherwise, the &lt;code&gt;admin&lt;/code&gt; database is used.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Given this order of operations, if the &lt;code&gt;SRV&lt;/code&gt; record resolves, but the &lt;code&gt;TXT&lt;/code&gt; record &lt;em&gt;doesn't&lt;/em&gt;, assuming the driver doesn't error out first the database provided in the connection string will be used for authentication. Using our original example of &lt;code&gt;mongodb+srv://&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@cluster0.abcde.mongodb.net/myFirstDatabase&lt;/code&gt;, the &lt;code&gt;myFirstDatabase&lt;/code&gt; database will be used to authenticate .... which will result in an authentication failure such as &lt;code&gt;MongoServerError: Authentication failed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, though MongoDB's drivers support automatic retryability of &lt;a href="https://www.mongodb.com/docs/manual/core/retryable-reads/"&gt;reads&lt;/a&gt; and &lt;a href="https://www.mongodb.com/docs/manual/core/retryable-writes/"&gt;writes&lt;/a&gt;, these DNS query failures aren't retryable. There is currently a project proposed (&lt;a href="https://jira.mongodb.org/browse/DRIVERS-2757"&gt;DRIVERS-2757&lt;/a&gt;) to improve this in the future, but for now these errors bubble up to the application immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can these issues be prevented?
&lt;/h2&gt;

&lt;p&gt;The best way to avoid these issues entirely is to just use the legacy &lt;a href="https://www.mongodb.com/docs/manual/reference/connection-string/#standard-connection-string-format"&gt;standard connection string format&lt;/a&gt;. If you're connecting to a replica set, the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst"&gt;server discovery and monitoring&lt;/a&gt; functionality of each driver will ensure topology changes are automatically discovered.&lt;/p&gt;

&lt;p&gt;Note that this will prevent new &lt;code&gt;mongos&lt;/code&gt;' from being discovered in a sharded cluster, however if you don't anticipate these to change frequently this will likely be a non-issue as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are other drivers affected?
&lt;/h2&gt;

&lt;p&gt;Failure to resolve DNS records can affect all MongoDB drivers, however it's highly unlikely you'll actually encounter this in a production setting. As there still remains a non-zero chance this issue will manifest, here are some examples of failures you may see from other drivers:&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby driver
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mongo::Error::NoSRVRecords: The DNS query returned no SRV records for 'cluster0.abcde.mongodb.net'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Java driver or Spring Boot MongoDB
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Example 1
Caused by: com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, srvResolutionException=com.mongodb.MongoConfigurationException: Unable to look up SRV record for host cluster0-shard-00-01.abcde.mongodb.net, servers=[]}


# Example 2
Caused by: com.mongodb.MongoConfigurationException: Unable to look up SRV record for host cluster0.abcde.mongodb.net
        at com.mongodb.internal.dns.DnsResolver.resolveHostFromSrvRecords(DnsResolver.java:79)
        at com.mongodb.ConnectionString.&amp;lt;init&amp;gt;(ConnectionString.java:321)
        at com.mongodb.MongoClientURI.&amp;lt;init&amp;gt;(MongoClientURI.java:234)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python driver
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Example 1
pymongo.errors.ConfigurationError: The DNS query name does not exist: _mongodb._tcp.cluster0.abcde.mongodb.net.

# Example 2
Exception has occurred: ConfigurationError
The DNS operation timed out after 20.001205682754517 seconds
dns.exception.Timeout: The DNS operation timed out after 20.001205682754517 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  C#/.NET driver
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Example 1
cluster0.abcde.mongodb.net IN TXT on x.x.x.x:53 timed out or is a transient error. A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

# Example 2
DnsClient.DnsResponseException:
at DnsClient.LookupClient.ResolveQuery (DnsClient, Version=1.6.0.0, Culture=neutral, PublicKeyToken=4574bb5573c51424)
at DnsClient.LookupClient.QueryInternal (DnsClient, Version=1.6.0.0, Culture=neutral, PublicKeyToken=4574bb5573c51424)
at DnsClient.LookupClient.Query (DnsClient, Version=1.6.0.0, Culture=neutral, PublicKeyToken=4574bb5573c51424)
at MongoDB.Driver.Core.Misc.DnsClientWrapper.ResolveTxtRecords (MongoDB.Driver.Core, Version=2.15.1.0, Culture=neutral, PublicKeyToken=null)
at MongoDB.Driver.Core.Configuration.ConnectionString.Resolve (MongoDB.Driver.Core, Version=2.15.1.0, Culture=neutral, PublicKeyToken=null)
at MongoDB.Driver.MongoUrl.Resolve (MongoDB.Driver, Version=2.15.1.0, Culture=neutral, PublicKeyToken=null)
at MongoDB.Driver.MongoClientSettings.FromUrl (MongoDB.Driver, Version=2.15.1.0, Culture=neutral, PublicKeyToken=null)

# Example 3
System.TimeoutException: A timeout occured after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0200000 } }. Client view of cluster state is { ClusterId : "1", ConnectionMode : "Automatic", Type : "Unknown", State : "Disconnected", Servers : [], DnsMonitorException : "DnsClient.DnsResponseException: Query 54148 =&amp;gt; _mongodb._tcp.cluster0.abcde.mongodb.net IN SRV on x.x.x.x:53 timed out or is a transient error.
 ---&amp;gt; System.Net.Sockets.SocketException (110): Connection timed out
   at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
   at DnsClient.DnsUdpMessageHandler.Query(IPEndPoint server, DnsRequestMessage request, TimeSpan timeout)
   at DnsClient.LookupClient.ResolveQuery(IReadOnlyList`1 servers, DnsQuerySettings settings, DnsMessageHandler handler, DnsRequestMessage request, LookupClientAudit audit)
   --- End of inner exception stack trace ---
   at DnsClient.LookupClient.ResolveQuery(IReadOnlyList`1 servers, DnsQuerySettings settings, DnsMessageHandler handler, DnsRequestMessage request, LookupClientAudit audit)
   at DnsClient.LookupClient.QueryInternal(DnsQuestion question, DnsQuerySettings queryOptions, IReadOnlyCollection`1 servers)
   at DnsClient.LookupClient.Query(DnsQuestion question)
   at DnsClient.LookupClient.Query(String query, QueryType queryType, QueryClass queryClass)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PHP driver
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fatal error: Uncaught MongoDB\Driver\Exception\InvalidArgumentException: Failed to parse URI options: Failed to look up SRV record "_mongodb._tcp.cluster0.abcde.mongodb.net": The requested name is valid but does not have an IP address.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Go driver
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error parsing command line options: error parsing uri: lookup cluster0.abcde.mongodb.net on x.x.x.x:53: cannot unmarshal DNS message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that (per the &lt;a href="https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#hdr-Potential_DNS_Issues"&gt;MongoDB Go driver documentation&lt;/a&gt;):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Building with Go 1.11+ and using connection strings with the &lt;code&gt;mongodb+srv&lt;/code&gt; scheme is unfortunately incompatible with some DNS servers in the wild due to the change introduced in &lt;a href="https://github.com/golang/go/issues/10622"&gt;https://github.com/golang/go/issues/10622&lt;/a&gt;. You may receive an error with the message "cannot unmarshal DNS message" while running an operation when using DNS servers that non-compliantly compress SRV records. Old versions of &lt;code&gt;kube-dns&lt;/code&gt; and the native DNS resolver (&lt;code&gt;systemd-resolver&lt;/code&gt;) on Ubuntu 18.04 are known to be non-compliant in this manner. We suggest using a different DNS server (8.8.8.8 is the common default), and, if that's not possible, avoiding the &lt;code&gt;mongodb+srv&lt;/code&gt; scheme.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  DNS is hard ...
&lt;/h2&gt;

&lt;p&gt;It sure can be, as intermittent/transient network events can also impact MongoDB drivers' ability to resolve DNS queries. The drivers (typically) rely on low-level OS APIs (such as &lt;a href="https://linux.die.net/man/3/getaddrinfo"&gt;&lt;code&gt;getaddrinfo&lt;/code&gt;&lt;/a&gt;) for network address and service translation. As such you may occasionally get errors such as &lt;code&gt;MongooseServerSelectionError: getaddrinfo EAI_AGAIN cluster0-shard-00-01.abcde.mongodb.net&lt;/code&gt; even when using the legacy (&lt;code&gt;mongodb://&lt;/code&gt;) URI scheme.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Footnotes&lt;/strong&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;small&gt;Sharded clusters could detect additions/removals of &lt;code&gt;mongos&lt;/code&gt;' if the driver(s) have implemented the &lt;a href="https://github.com/mongodb/specifications/blob/master/source/polling-srv-records-for-mongos-discovery/polling-srv-records-for-mongos-discovery.rst"&gt;polling &lt;code&gt;SRV&lt;/code&gt; records for &lt;code&gt;mongos&lt;/code&gt; discovery&lt;/a&gt; specification&lt;/small&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>mongodb</category>
      <category>dns</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>Identifying Ruby Developers' Favourite IDEs for Ruby/Rails in 2023</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Wed, 03 May 2023 20:44:38 +0000</pubDate>
      <link>https://dev.to/alexbevi/identifying-ruby-developers-favourite-ides-for-rubyrails-in-2023-3h4k</link>
      <guid>https://dev.to/alexbevi/identifying-ruby-developers-favourite-ides-for-rubyrails-in-2023-3h4k</guid>
      <description>&lt;p&gt;As a Product Manager, data is everything when it comes to making decisions. One of my responsibilities as a PM for Developer Interfaces is to understand how our developer communities work most effectively, and what their preferred tooling and stacks look like.&lt;/p&gt;

&lt;p&gt;When focusing on the Ruby developer community, a simple question to ask would be &lt;em&gt;"What is your favourite editor/IDE when working with Ruby / Rails?"&lt;/em&gt; JetBrains' developer survey from 2021 found that &lt;a href="https://www.jetbrains.com/lp/devecosystem-2021/ruby/#Ruby_what-editor-ide-do-you-mostly-use-for-ruby-development"&gt;48% of Ruby developers mostly use RubyMine&lt;/a&gt; - which may be accurate - but the survey was run by the vendor responsible for RubyMine and may have skewed results based on their sample group consisting of fans/customers/users of their products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;I wanted to try running my own survey to see if the responses align with what JetBrains found. Since my &lt;a href="https://www.reddit.com/r/rails/comments/12yjgwh/favorite_editoride_when_working_with_ruby_rails/"&gt;Reddit survey&lt;/a&gt; was conducted 2 years after JetBrains' how have things changed?&lt;/p&gt;

&lt;p&gt;This was my first time running a Reddit poll, but found the community to be extremely engaged and willing to provide honest and targeted feedback. I only setup the poll to run for 72 hours, but during that time period I received:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;931 Votes&lt;/li&gt;
&lt;li&gt;20K Total Views&lt;/li&gt;
&lt;li&gt;50 Upvotes&lt;/li&gt;
&lt;li&gt;41 Comments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately Reddit doesn't appear to consistently present engagement statistics (views, upvotes) so this is an approximation based on observation during the period the poll was open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;The poll contained 6 options (the maximum Reddit allows) and was open from 2023-04-25 to 2023-04-28.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdt17kac7rg0zu1jbcqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdt17kac7rg0zu1jbcqe.png" alt="Image description" width="665" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on feedback I'd received in the comments I updated &lt;a href="https://www.vim.org/"&gt;Vim&lt;/a&gt; to also include &lt;a href="https://neovim.io/"&gt;Neovim&lt;/a&gt;, however I'd have preferred to keep these options separate.&lt;/p&gt;

&lt;p&gt;The fact that &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt; was almost half of the poll's respondents favourite editor wasn't surprising, however over a quarter still favoured &lt;a href="https://www.jetbrains.com/ruby/"&gt;RubyMine&lt;/a&gt;. This is far less that what JetBrains found, but my sample size is much smaller and audience potentially more diverse. Still the size of the user base for RubyMine is large enough that it should not be discounted when developing strategies when discussing developer tooling for Ruby specifically!&lt;/p&gt;

&lt;h2&gt;
  
  
  Outcome
&lt;/h2&gt;

&lt;p&gt;The goal of this exercise was to learn 2 things specifically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Based on Reddit, what are Ruby developers favourite IDEs or Editors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The main IDEs/Editors currently favoured by the users I polled were Visual Studio Code, Neovim and RubyMine. I had an entry in the poll of &lt;em&gt;"Other"&lt;/em&gt;, which I believe (based on the comments) is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://macromates.com/"&gt;Textmate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/atom"&gt;Atom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://notepad-plus-plus.org/"&gt;Notepad++&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Developers also seem to prefer editors that support &lt;a href="https://solargraph.org/"&gt;Solargraph&lt;/a&gt; for Intellisense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Reddit a good platform for this type of exercise&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Depending on the community/subreddit you choose to run the poll in your mileage may vary. The &lt;a href="https://www.reddit.com/r/rails/"&gt;r/rails&lt;/a&gt; subreddit has 57K users, so the chances of getting decent engagement were moderate, and given that I only ran this poll for 3 days I feel the response rate was quite high.&lt;/p&gt;

&lt;p&gt;I will definitely use this method again in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When promoting this poll I posted to LinkedIn and Twitter only. Some of the feedback I got alluded to Reddit potentially discouraging some participation as users may not have accounts and may not want to create an account just to vote in a poll. Further to this, Reddit limits the number of items you can include in your poll to 6 items and it seems &lt;a href="https://www.reddit.com/r/ModSupport/comments/hach42/why_is_there_a_6choice_poll_limit/"&gt;this is by design and won't be increased any time soon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Being able to capture feedback from participants without there being a barrier to entry (like creating an account on Reddit) may improve engagement, however there is definite value in targeting a poll directly to the community represented in a subreddit.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>developer</category>
      <category>product</category>
    </item>
    <item>
      <title>MongoDB ORMs, ODMs, and Libraries</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Tue, 01 Nov 2022 18:57:54 +0000</pubDate>
      <link>https://dev.to/alexbevi/mongodb-orms-odms-and-libraries-aj0</link>
      <guid>https://dev.to/alexbevi/mongodb-orms-odms-and-libraries-aj0</guid>
      <description>&lt;p&gt;Though developers have always been capable of manually writing complex queries to interact with a database, this approach can be tedious and error-prone. &lt;a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping"&gt;Object-Relational Mappers&lt;/a&gt; (or ORMs) improve the developer experience, as they accomplish multiple meaningful tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facilitating interactions between the database and an application by abstracting away the need to write raw SQL or database query language.&lt;/li&gt;
&lt;li&gt;Managing serialization/deserialization of data to objects.&lt;/li&gt;
&lt;li&gt;Enforcement of schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, while it’s true that MongoDB offers &lt;a href="https://www.mongodb.com/docs/drivers/"&gt;Drivers&lt;/a&gt; with idiomatic APIs and helpers for most  programming languages, sometimes a higher level abstraction is desirable. Developers are used to interacting with data in a more declarative fashion (LINQ for C#, ActiveRecord for Ruby, etc.) and an ORM facilitates code maintainability and reuse by allowing developers to interact with data as objects.&lt;/p&gt;

&lt;p&gt;MongoDB provides a number of ORM-like libraries, and our &lt;a href="https://www.mongodb.com/docs/drivers/community-supported-drivers/"&gt;community&lt;/a&gt; and partners have as well! These are sometimes referred to as ODMs (Object Document Mappers), as MongoDB is not a relational database management system. However, they exist to solve the same problem as ORMs do and the terminology can be used interchangeably.&lt;/p&gt;

&lt;p&gt;The following are some examples of the best MongoDB ORM or ODM libraries for a number of programming languages, including Ruby, Python, Java, Node.js, and PHP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beanie
&lt;/h2&gt;

&lt;p&gt;Beanie is an Asynchronous Python object-document mapper (ODM) for MongoDB, based on &lt;a href="https://www.mongodb.com/docs/drivers/motor/"&gt;Motor&lt;/a&gt; (an asynchronous MongoDB driver) and &lt;a href="https://pydantic-docs.helpmanual.io/"&gt;Pydantic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When using Beanie, each database collection has a corresponding document that is used to interact with that collection. In addition to retrieving data, Beanie allows you to add, update, and delete documents from the collection. Beanie saves you time by removing boilerplate code, and it helps you focus on the parts of your app that actually matter.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://beanie-odm.dev/"&gt;Beanie documentation&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doctrine
&lt;/h2&gt;

&lt;p&gt;Doctrine is a PHP MongoDB ORM, even though it’s referred to as an ODM. This library provides PHP object mapping functionality and transparent persistence for PHP objects to MongoDB, as well as a mechanism to map embedded or referenced documents. It can also create references between PHP documents in different databases and work with GridFS buckets.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/index.html"&gt;Doctrine MongoDB ODM documentation&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mongoid
&lt;/h2&gt;

&lt;p&gt;Most Ruby-based applications are built using the &lt;a href="https://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; framework. As a result, Rails’ &lt;a href="https://guides.rubyonrails.org/active_record_basics.html"&gt;Active Record&lt;/a&gt; implementation, conventions, CRUD API, and callback mechanisms are second nature to Ruby developers. So, as far as a MongoDB ORM for Ruby, the Mongoid ODM provides API parity wherever possible to ensure developers working with a Rails application and using MongoDB can do so using methods and mechanics they’re already familiar with.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://www.mongodb.com/docs/mongoid/current/"&gt;Mongoid documentation&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mongoose
&lt;/h2&gt;

&lt;p&gt;If you’re seeking an ORM for NodeJS and MongoDB, look no further than Mongoose. This Node.js-based Object Data Modeling (ODM) library for MongoDB is akin to an Object Relational Mapper (ORM) such as &lt;a href="https://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt;. The problem that Mongoose aims to solve is allowing developers to enforce a specific schema at the application layer. In addition to enforcing a schema, Mongoose also offers a variety of hooks, model validation, and other features aimed at making it easier to work with MongoDB.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://mongoosejs.com/"&gt;Mongoose documentation&lt;/a&gt; or &lt;a href="https://www.mongodb.com/developer/languages/javascript/mongoose-versus-nodejs-driver/"&gt;MongoDB &amp;amp; Mongoose: Compatibility and Comparison&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  MongoEngine
&lt;/h2&gt;

&lt;p&gt;MongoEngine is a Python ORM for MongoDB. Branded as a Document-Object Mapper, it uses a simple declarative API, similar to the Django ORM.&lt;/p&gt;

&lt;p&gt;It was first released in 2015 as an open-source project, and the current version is built on top of &lt;a href="https://www.mongodb.com/docs/drivers/pymongo/"&gt;PyMongo&lt;/a&gt;, the official Python Driver by MongoDB.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="http://mongoengine.org/"&gt;MongoEngine documentation&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prisma
&lt;/h2&gt;

&lt;p&gt;Prisma is a &lt;a href="https://www.prisma.io/docs/concepts/overview/prisma-in-your-stack/is-prisma-an-orm"&gt;new kind of ORM&lt;/a&gt; for Node.js and Typescript that fundamentally differs from traditional ORMs. With Prisma, you define your models in the declarative &lt;a href="https://www.prisma.io/docs/concepts/components/prisma-schema"&gt;Prisma schema&lt;/a&gt;, which serves as the single source of truth for your database schema and the models in your programming language. The Prisma Client will read and write data to your database in a type-safe manner, without the overhead of managing complex model instances. This makes the process of querying data a lot more natural as well as more predictable since Prisma Client always returns plain JavaScript objects.&lt;/p&gt;

&lt;p&gt;Support for MongoDB was one of the most requested features since the initial release of the Prisma ORM, and was added in version 3.12.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://www.prisma.io/mongodb"&gt;Prisma &amp;amp; MongoDB&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring Data MongoDB
&lt;/h2&gt;

&lt;p&gt;If you’re seeking a Java ORM for MongoDB, Spring Data for MongoDB is the most popular choice for Java developers. The &lt;a href="https://spring.io/projects/spring-data"&gt;Spring Data&lt;/a&gt; project provides a familiar and consistent Spring-based programming model for new datastores while retaining store-specific features and capabilities.&lt;/p&gt;

&lt;p&gt;Key functional areas of Spring Data MongoDB that Java developers will benefit from are a POJO centric model for interacting with a MongoDB DBCollection and easily writing a repository-style data access layer.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://spring.io/projects/spring-data-mongodb"&gt;Spring Data MongoDB documentation&lt;/a&gt; or the &lt;a href="https://www.mongodb.com/compatibility/spring-boot"&gt;Spring Boot Integration with MongoDB Tutorial&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go Build Something Awesome!
&lt;/h2&gt;

&lt;p&gt;Though not an exhaustive list of the available MongoDB ORM and ODM libraries available right now, the entries above should allow you to get started using MongoDB in your language of choice more naturally and efficiently.&lt;/p&gt;

&lt;p&gt;If you’re looking for assistance or have any feedback don’t hesitate to engage on our &lt;a href="https://www.mongodb.com/community/forums/"&gt;Community Forums&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>orm</category>
      <category>odm</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Bug Hunting with the MongoDB Haskell Community</title>
      <dc:creator>Alex Bevilacqua</dc:creator>
      <pubDate>Wed, 21 Sep 2022 17:28:59 +0000</pubDate>
      <link>https://dev.to/alexbevi/bug-hunting-with-the-mongodb-haskell-community-469j</link>
      <guid>https://dev.to/alexbevi/bug-hunting-with-the-mongodb-haskell-community-469j</guid>
      <description>&lt;p&gt;MongoDB currently maintains 10 programming language &lt;a href="https://www.mongodb.com/docs/drivers/"&gt;Drivers&lt;/a&gt; in-house, including a &lt;a href="https://www.mongodb.com/docs/ruby-driver/current/"&gt;Ruby&lt;/a&gt; driver for which I'm presently the Product Manager. Additionally we also have a library of &lt;a href="https://www.mongodb.com/docs/drivers/community-supported-drivers/"&gt;community maintained drivers&lt;/a&gt;, built using the &lt;a href="https://github.com/mongodb/specifications/tree/master/source"&gt;MongoDB Driver specifications&lt;/a&gt; our engineers maintain and publish.&lt;/p&gt;

&lt;p&gt;It was brought to my attention that one of these community drivers - the &lt;a href="https://github.com/mongodb-haskell/mongodb"&gt;Haskell driver&lt;/a&gt; - was experiencing an issue whereby queries were no longer returning results from the &lt;a href="https://www.mongodb.com/docs/atlas/"&gt;MongoDB Atlas&lt;/a&gt; clusters their applications were connected to.&lt;/p&gt;

&lt;p&gt;Though I've never worked with &lt;a href="https://www.haskell.org/"&gt;Haskell&lt;/a&gt;, before joining the team I worked in &lt;a href="https://dev.to%20post_url%202018-10-01-technical-services-engineering-at-mongodb%20"&gt;Technical Services&lt;/a&gt; providing support for customers experiencing problems with their applications via our drivers. This seemed like an interesting problem we could hopefully solve for our developer community so I'd like to share the diagnostic journey that lead us to the issue and ultimately enabled a resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;When &lt;a href="https://github.com/why-not-try-calmer"&gt;Adrien&lt;/a&gt; first reported &lt;a href="https://github.com/mongodb-haskell/mongodb/issues/131"&gt;issue #131 on GitHub&lt;/a&gt; the initial assessment was that their application could successfully connect to a MongoDB Atlas cluster and write new content, but when trying to read those results back the result set was always empty. This had happened suddenly causing existing applications and workloads to break however no new code had been introduced which could potentially be the culprit.&lt;/p&gt;

&lt;p&gt;As I'm unfamiliar with Haskell Adrien kindly provided a &lt;a href="https://github.com/why-not-try-calmer/test-mongo"&gt;Dockerized reproduction&lt;/a&gt; I could use to test this issue against my own Atlas clusters. This reproduction would write 3 documents to a collection, then try to read 3 documents back. To begin testing I setup an M10 cluster and ran the tests a few times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failures:

  src/Lib.hs:101:33:
  1) Reads Ensures reads work
       expected: 3
        but got: 9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each time I ran the test it would fail, but the number of documents in the &lt;em&gt;"Ensures reads work"&lt;/em&gt; that were received kept increasing. The cluster I was testing on was a dedicated cluster, however MongoDB Atlas also offers free and shared tier clusters so for completeness of testing I configured an M0 next and re-ran the tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failures:

  src/Lib.hs:101:33:
  1) Reads Ensures reads work
       expected: 3
        but got: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No matter how many times I ran the tests against my M0 (also tested M2 and M5) the results were always 0.&lt;/p&gt;

&lt;p&gt;Just to make sure this wasn't a larger issue I tested with a script that uses the Ruby driver against an M0 cluster to verify the behavior didn't reproduce there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'bundler/inline'&lt;/span&gt;

&lt;span class="n"&gt;gemfile&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s1"&gt;'https://rubygems.org'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'mongo'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Mongo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mongodb+srv://....mongodb.net/test'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:foo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Found &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; documents"&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; Found 0 documents&lt;/span&gt;

&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_many&lt;/span&gt;&lt;span class="p"&gt;([].&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"baz"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Found &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; documents"&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; Found 3 documents&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script would produce the expected result, which further pointed to a potential issue on the Atlas side that was specific to free and shared tier clusters.&lt;/p&gt;

&lt;p&gt;MongoDB Atlas imposes some &lt;a href="https://www.mongodb.com/docs/atlas/reference/free-shared-limitations/"&gt;limitations on free and shared tier&lt;/a&gt; clusters, which in some cases are enforced by a proxy layer between the application and the underlying infrastructure backing the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;Now that the issue was narrowed down, working with a Cloud Operations Engineer to create an isolated M2 cluster in a development environment, we increased the &lt;a href="https://www.mongodb.com/docs/manual/reference/log-messages/#verbosity-levels"&gt;log verbosity&lt;/a&gt; for that cluster for &lt;a href="https://www.mongodb.com/docs/manual/reference/log-messages/#mongodb-data-QUERY"&gt;&lt;code&gt;QUERY&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.mongodb.com/docs/manual/reference/log-messages/#mongodb-data-COMMAND"&gt;&lt;code&gt;COMMAND&lt;/code&gt;&lt;/a&gt; log components.&lt;/p&gt;

&lt;p&gt;With this information, when we download logs for the node our test is targeting we should be able to get a lot more information as to what was being executed and where it might be failing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Test #1&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2022-08-18T11:19:16.985+00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;D2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;COMMAND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5578800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ctx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;conn24194&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deprecated operation requested. The client driver may require an upgrade in order to ensure compatibility with future server versions. For more details see https://dochub.mongodb.org/core/legacy-opcode-compatibility&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;op&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clientInfo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;driver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongo-go-driver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;v1.7.2+prerelease&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;linux&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;architecture&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arm64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;platform&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;go1.18.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Atlas Proxy v20220824.0.0.1660656950&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}}}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2022-08-18T11:19:16.986+00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;D2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;QUERY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20914&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ctx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;conn24194&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Running query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ns: 62fe1f7d37518e1c32149694_haskell.test123 query: { comment: { AtlasProxyAppName: &lt;/span&gt;&lt;span class="se"&gt;\"\"&lt;/span&gt;&lt;span class="s2"&gt;, AtlasProxyClientMetadata: {} } } sort: {} projection: {}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2022-08-18T11:19:16.986+00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;D5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;QUERY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20917&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ctx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;conn24194&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not caching executor but returning results&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numResults&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on log analysis we could not only verify the issue existed, but why it was affecting these operations from the Haskell driver:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A deprecated operation was being run&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MongoDB uses a &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/"&gt;wire protocol&lt;/a&gt; when sending/receiving messages internally and externally (via Drivers). Initially a number of &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/#opcodes"&gt;opcodes&lt;/a&gt; existed, but starting with MongoDB 5.0 most of these were deprecated in favor of &lt;a href="https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/#op_msg"&gt;&lt;code&gt;OP_MSG&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Prior to MongoDB 3.6 when &lt;a href="https://www.mongodb.com/docs/v5.0/release-notes/3.6/#wire-protocol-and-compression"&gt;&lt;code&gt;OP_MSG&lt;/code&gt; was introduced&lt;/a&gt; to subsume existing opcodes, query operations were executed via &lt;a href="https://www.mongodb.com/docs/manual/legacy-opcodes/#op_query"&gt;&lt;code&gt;OP_QUERY&lt;/code&gt;&lt;/a&gt;, which the Haskell driver is apparently still using for query execution.&lt;/p&gt;

&lt;p&gt;Note that though &lt;code&gt;OP_QUERY&lt;/code&gt; is deprecated, it would still be supported in the version of MongoDB we were testing (5.0) and as such is not the cause of this problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The logs confirm no results are being returned by the query&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the default level, the &lt;a href="https://www.mongodb.com/docs/manual/tutorial/manage-the-database-profiler/"&gt;Database Profiler&lt;/a&gt; will only output queries to the &lt;code&gt;mongod&lt;/code&gt; logs if they exceed the slow query threshold (&lt;a href="https://www.mongodb.com/docs/manual/reference/method/db.setProfilingLevel/#std-label-set-profiling-level-options-slowms"&gt;&lt;code&gt;slowms&lt;/code&gt;&lt;/a&gt;) of 100ms. The tests we were running would likely have completed in under 10ms, which prevented anything useful from being logged.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;{"t":{"$date":"2022-08-18T11:19:16.986+00:00"},"s":"D5", "c":"QUERY",    "id":20917,   "ctx":"conn24194","msg":"Not caching executor but returning results","attr":{"numResults":0}}&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once the log level was increased it was apparent that the operation in question was being executed, but was not returning any results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The logs highlight an issue with the query itself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the log level increased however the &lt;code&gt;QUERY&lt;/code&gt; component logs showed clearly that not only were no results being returned, but the query &lt;em&gt;shape&lt;/em&gt; that was being sent to the server didn't match what we expected:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;{"t":{"$date":"2022-08-18T11:19:16.986+00:00"},"s":"D2", "c":"QUERY",    "id":20914,   "ctx":"conn24194","msg":"Running query","attr":{"query":"ns: 62fe1f7d37518e1c32149694_haskell.test123 query: { comment: { AtlasProxyAppName: \"\", AtlasProxyClientMetadata: {} } } sort: {} projection: {}"}}&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It appeared that the query's filter - which we expected to be empty - was in fact filtering for &lt;code&gt;comment: { AtlasProxyAppName: "", AtlasProxyClientMetadata: {} }&lt;/code&gt;. Since none of the sample documents that were being created as part of this test matched these criteria, the query returned 0 results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Findings
&lt;/h2&gt;

&lt;p&gt;From our log analysis it would appear our operations were being rewritten to append a filter criteria for a &lt;code&gt;comment&lt;/code&gt; field with a value of &lt;code&gt;{ AtlasProxyAppName: "", AtlasProxyClientMetadata: {} }&lt;/code&gt;. As &lt;code&gt;comment&lt;/code&gt; has a specific meaning within the context of MongoDB commands it was becoming apparent what the issue was and where it may have originated.&lt;/p&gt;

&lt;p&gt;Starting with &lt;a href="https://www.mongodb.com/docs/manual/release-notes/4.4/#comment-option-available-to-all-database-commands"&gt;MongoDB 4.4, a &lt;code&gt;comment&lt;/code&gt; option was added to all database commands&lt;/a&gt; (see &lt;a href="https://jira.mongodb.org/browse/SERVER-29794"&gt;SERVER-29794&lt;/a&gt;).&lt;br&gt;
This was not be confused with the &lt;a href="https://www.mongodb.com/docs/v4.2/reference/operator/meta/comment/"&gt;&lt;code&gt;$comment&lt;/code&gt; meta operator&lt;/a&gt; that has been available &lt;a href="https://jira.mongodb.org/browse/SERVER-2515"&gt;since MongoDB 2.0&lt;/a&gt; for propagating metadata to query logs.&lt;/p&gt;

&lt;p&gt;The Atlas team introduced a feature (released &lt;code&gt;2022-06-22&lt;/code&gt;) that would utilize these comments to improve the &lt;a href="https://www.mongodb.com/docs/manual/reference/command/currentOp/"&gt;&lt;code&gt;currentOp&lt;/code&gt;&lt;/a&gt; output in free/shared clusters. As all "official" MongoDB Drivers communicate with modern MongoDB clusters using &lt;code&gt;OP_MSG&lt;/code&gt;, when this feature was being tested there were no issues.&lt;/p&gt;

&lt;p&gt;Unfortunately, drivers that still use &lt;code&gt;OP_QUERY&lt;/code&gt; to make queries were negatively impacted as a result of the metadata comment injection occurring in the filter instead of one level above as is the case for &lt;code&gt;OP_MSG&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that the issue could be verified, additional logic was introduced to use the &lt;code&gt;$comment&lt;/code&gt; meta operator if an &lt;code&gt;OP_QUERY&lt;/code&gt; was detected instead of improperly applying a &lt;code&gt;comment&lt;/code&gt; option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outcome
&lt;/h2&gt;

&lt;p&gt;With the assistance of the Haskell community we were able to identify and address a deficiency in the free and shared tiers of MongoDB Atlas. The fix for this was released in version &lt;code&gt;8ed75a4810@v20220914&lt;/code&gt; on 2022-09-21, and any Haskell application using the community maintained Haskell driver should have started working as expected without the need for additional intervention.&lt;/p&gt;

&lt;p&gt;We truly appreciate the investment our developer communities make when they put time and effort into building something as powerful as a MongoDB driver and want to ensure we do what we can to offer assistance if possible.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>haskell</category>
      <category>community</category>
      <category>devrel</category>
    </item>
  </channel>
</rss>
