{"id":1719,"date":"2026-02-04T23:10:05","date_gmt":"2026-02-04T23:10:05","guid":{"rendered":"https:\/\/craftcookcode.com\/?p=1719"},"modified":"2026-02-04T23:10:08","modified_gmt":"2026-02-04T23:10:08","slug":"now-qlik-replicate-and-mongodb-are-stuck-inside-containers","status":"publish","type":"post","link":"https:\/\/craftcookcode.com\/?p=1719","title":{"rendered":"Now Qlik Replicate and MongoDB are stuck inside containers"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">That message from my Manager<\/h2>\n\n\n\n<p>I got a message from my manager unexpectedly.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u201cHey. A team is converting a MSSQL database to MongoDB.&nbsp; Can Qlik Replicate capture deletes from the MongoDB?\u201d<\/p>\n<\/blockquote>\n\n\n\n<p>I thought this was an abnormal question; why wouldn\u2019t QR support deletes?<\/p>\n\n\n\n<p>Not wanting to make an assumption that may be false and have profound consequences later in a conversion project, I looked up the Qlik documentation.&nbsp;<\/p>\n\n\n\n<p>Nothing in the documented <a href=\"https:\/\/help.qlik.com\/en-US\/replicate\/November2025\/Content\/Replicate\/Main\/MongoDB_Source\/mongodb_limitations.htm\" target=\"_blank\" rel=\"noopener\" title=\"\">\u201cLimitations and considerations.\u201d<\/a><\/p>\n\n\n\n<p>Just as a safeguard I also did a google search and a forum search to see if anything else turned up.<\/p>\n\n\n\n<p>Again nothing.<\/p>\n\n\n\n<p>I pinged back to my manager.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u201cQR should capture deletes simply fine.&nbsp; Where did you hear that QR had problems with MongoDB deletes from?\u201d<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u201cOh.&nbsp; The project manager heard from a Mongo guy that Qlik does not work.\u201d<\/p>\n<\/blockquote>\n\n\n\n<p>I bit my lip.&nbsp; To me that seemed the same as getting health advice off a random guy at the pub who saw something on Telegram.<\/p>\n\n\n\n<p>But I realised now that even though I had official Qlik documentation backing me up; the burden of proof was back on me.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Back into the world of containers<\/h2>\n\n\n\n<p><a href=\"https:\/\/craftcookcode.com\/?p=1507\" target=\"_blank\" rel=\"noopener\" title=\"\">Qlik Replicate in a docker container<\/a> has been an extremely useful tool on my Linux development machine.\u00a0 It enables me to quickly test various aspects of QR without interrupting the official dev environment; or fighting with the cloud team to get a proof-of-concept source system set up.<\/p>\n\n\n\n<p>First, I had to set up a MongoDB docker container.\u00a0 Specifically, the MongoDB had to have a \u201creplica\u201d; a standalone wouldn\u2019t work.  Since this was a POC; I didn&#8217;t need a fully fledge &#8211; multi replica &#8211; ultra secure cluster; just something simple and disposable.<\/p>\n\n\n\n<p>After fumbling around with a number of examples (Gemeni \u2013 how could you fail me!); I came across a page by \u201cGink\u201d titled \u201c<a href=\"https:\/\/ginkcode.com\/post\/how-to-set-up-mongodb-with-replica-set-via-docker-compose\" target=\"_blank\" rel=\"noopener\" title=\"\">How to set up MongoDB with replica set via Docker Compose?<\/a>\u201d<\/p>\n\n\n\n<p>It was simple and had exactly what I needed.\u00a0<\/p>\n\n\n\n<p><strong>Dockerfile:<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nFROM mongo:7.0\nRUN openssl rand -base64 756 &gt; \/etc\/mongo-keyfile \nRUN chmod 400 \/etc\/mongo-keyfile \nRUN chown mongodb:mongodb \/etc\/mongo-keyfile \n<\/pre><\/div>\n\n\n<p><strong>docker-compose.yml:<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\n# From https:\/\/ginkcode.com\/post\/how-to-set-up-mongodb-with-replica-set-via-docker-compose\nversion: &#039;3.8&#039;\n \nservices:\n  mongo:\n    build:\n      context: .\n      dockerfile: Dockerfile\n    container_name: mongodb-replicaset\n    restart: always\n    environment:\n      MONGO_INITDB_ROOT_USERNAME: root\n      MONGO_INITDB_ROOT_PASSWORD: root\n    ports:\n      - 27017:27017\n    command: --replSet rs0 --keyFile \/etc\/mongo-keyfile --bind_ip_all --port 27017\n    healthcheck:\n      test: echo &quot;try { rs.status() } catch (err) { rs.initiate({_id:&#039;rs0&#039;,members:&#x5B;{_id:0,host:&#039;127.0.0.1:27017&#039;}]}) }&quot; | mongosh --port 27017 -u root -p root --authenticationDatabase admin\n      interval: 5s\n      timeout: 15s\n      start_period: 15s\n      retries: 10\n    volumes:\n      - data:\/data\/db\n \nvolumes:\n  data: {}\n<\/pre><\/div>\n\n\n<p><strong>Connection string<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nmongodb:\/\/root:root@localhost:27017\/?authSource=admin\n<\/pre><\/div>\n\n\n<p>Please visit Gink&#8217;s page <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Connecting to Qlik Replicate<\/h3>\n\n\n\n<p>The great thing is that we don&#8217;t have to mess around installing extra ODBC drivers that can make the Qlik Replicate docker image complex.<\/p>\n\n\n\n<p>So with the MongoDB and the Qlik Replicate docker containers up and running; we can how create a new endpoint with the following settings:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Field<\/strong><\/td><td><strong>Variable<\/strong><\/td><\/tr><tr><td>MongoDB Deployment<\/td><td>Standard<\/td><\/tr><tr><td>Hosts<\/td><td>host.docker.internal<\/td><\/tr><tr><td>Authentication Method<\/td><td>SCRAM-SHA-256<\/td><\/tr><tr><td>Username<\/td><td>root<\/td><\/tr><tr><td>Password<\/td><td>root<\/td><\/tr><tr><td>Authentication database name<\/td><td>admin<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"968\" src=\"https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_02-1024x968.png\" alt=\"\" class=\"wp-image-1723\" srcset=\"https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_02-1024x968.png 1024w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_02-300x284.png 300w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_02-768x726.png 768w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_02.png 1248w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>A test connection confirmed that the connection was working as expected.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Proving that deletes are working<\/h2>\n\n\n\n<p>Getting close to resolving the burden of proof.\u00a0 I got our GenAI to create a simple python script to add, update, and delete some data from the Mongo Database and set it running:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nimport pymongo\nimport random\nimport string\nimport time\n\ndef generate_random_string(length=10):\n    &quot;&quot;&quot;Generate a random string of fixed length.&quot;&quot;&quot;\n    letters = string.ascii_lowercase\n    return &#039;&#039;.join(random.choice(letters) for i in range(length))\n\ndef add_random_data(collection):\n    &quot;&quot;&quot;Adds a new document with random data to the collection.&quot;&quot;&quot;\n    \n    new_document = {\n        &quot;name&quot;: generate_random_string(),\n        &quot;age&quot;: random.randint(18, 99),\n        &quot;email&quot;: f&quot;{generate_random_string(5)}@example.com&quot;\n    }\n    \n    result = collection.insert_one(new_document)\n\n    print(f&quot;Added: {result.inserted_id}&quot;)\n\ndef update_random_data(collection):\n    &quot;&quot;&quot;Updates a random document in the collection.&quot;&quot;&quot;\n    if collection.count_documents({}) &gt; 0:\n        # Get a random document using the $sample aggregation operator\n        try:\n            random_doc_cursor = collection.aggregate(&#x5B;{&quot;$sample&quot;: {&quot;size&quot;: 1}}])\n            random_doc = next(random_doc_cursor)\n            new_age = random.randint(18, 99)\n            \n            collection.update_one(\n                {&quot;_id&quot;: random_doc&#x5B;&quot;_id&quot;]},\n                {&quot;$set&quot;: {&quot;age&quot;: new_age}}\n            )\n\n            print(f&quot;Updated: {random_doc&#x5B;&#039;_id&#039;]} with new age {new_age}&quot;)\n        except StopIteration:\n            print(&quot;Could not find a document to update.&quot;)\n    else:\n        print(&quot;No documents to update.&quot;)\n\ndef delete_random_data(collection):\n    &quot;&quot;&quot;Deletes a random document from the collection.&quot;&quot;&quot;\n    if collection.count_documents({}) &gt; 0:\n        # Get a random document using the $sample aggregation operator\n        try:\n            random_doc_cursor = collection.aggregate(&#x5B;{&quot;$sample&quot;: {&quot;size&quot;: 1}}])\n            random_doc = next(random_doc_cursor)\n\n            collection.delete_one({&quot;_id&quot;: random_doc&#x5B;&quot;_id&quot;]})\n            \n            print(f&quot;Deleted: {random_doc&#x5B;&#039;_id&#039;]}&quot;)\n        except StopIteration:\n            print(&quot;Could not find a document to delete.&quot;)\n    else:\n        print(&quot;No documents to delete.&quot;)\n\n\nif __name__ == &quot;__main__&quot;:\n    print(&quot;Starting script... Press Ctrl+C to stop.&quot;)\n\n    try:\n        client = pymongo.MongoClient(&quot;mongodb:\/\/root:root@localhost:27017\/?authSource=admin&quot;)\n        db = client&#x5B;&quot;random_data_db&quot;]\n        collection = db&#x5B;&quot;my_collection&quot;]\n        # The ismaster command is cheap and does not require auth.\n        client.admin.command(&#039;ismaster&#039;)\n        print(&quot;MongoDB connection successful.&quot;)\n    except pymongo.errors.ConnectionFailure as e:\n        print(f&quot;Could not connect to MongoDB: {e}&quot;)\n        exit()\n\n    while True:\n        try:\n            add_random_data(collection)\n            add_random_data(collection)\n            add_random_data(collection)\n\n            update_random_data(collection)\n            delete_random_data(collection)\n            \n            # Wait for five seconds before the next cycle\n            time.sleep(5)\n\n        except KeyboardInterrupt:\n            print(&quot;\\nScript stopped by user.&quot;)\n            break\n        except Exception as e:\n            print(f&quot;An error occurred: {e}&quot;)\n            break\n\n    # Close the connection\n    client.close()\n    print(&quot;MongoDB connection closed.&quot;)\n\n<\/pre><\/div>\n\n\n<p>With the script running and adding, updating and deleting data to the MongoDB; a QR task can be created to read from the database &#8220;random_data_db&#8221; and collection &#8220;my_collection&#8221;<\/p>\n\n\n\n<p>And voil\u00e0. Data is flowing through Qlik Replicate from the MongoDB.<\/p>\n\n\n\n<p>And more importantly deletes are getting picked up as expected.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"312\" src=\"https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_03-1024x312.png\" alt=\"\" class=\"wp-image-1727\" srcset=\"https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_03-1024x312.png 1024w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_03-300x92.png 300w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_03-768x234.png 768w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_03-1536x469.png 1536w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2026\/02\/code_qr_mongo_03-2048x625.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p> <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; title: ; notranslate\" title=\"\">\n{\n\t&quot;header__change_seq&quot;:&quot;20260204052516000000000000000004085&quot;,\n\t&quot;header__change_oper&quot;:&quot;D&quot;,&quot;header__change_mask&quot;:&quot;80&quot;,\n\t&quot;header__stream_position&quot;:&quot;6982d83c:00000005:00000000&quot;,\n\t&quot;header__operation&quot;:&quot;DELETE&quot;,\n\t&quot;header__transaction_id&quot;:&quot;4155544F434F4D4D4954000000000000&quot;,\n\t&quot;header__timestamp&quot;:&quot;2026-02-04 05:25:16.000000&quot;,\n\t&quot;_id&quot;:&quot;6982d8186b2cc5ee1a161d13&quot;,\n\t&quot;_doc&quot;:&quot;{\\&quot;_id\\&quot;: {\\&quot;$oid\\&quot;: \\&quot;6982d8186b2cc5ee1a161d13\\&quot;}}&quot;\n}\n \n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Conclusion <\/h2>\n\n\n\n<p>And voil\u00e0. Data is flowing through Qlik Replicate from the MongoDB.<\/p>\n\n\n\n<p>And more importantly; deletes are getting picked up as expected.<\/p>\n\n\n\n<p>If you have come to my humble website after googling \u201cCan Qlik Replicate replicate deletes from a MongoDB?\u201d well, the answer is \u201cYes \u2013 Yes it can.\u201d<\/p>\n\n\n\n<p>I can only speculate where that rumour came from.&nbsp; Maybe it was from an older version of QR or MongoDB that the person in question was referring to?&nbsp; Or some very abnormal setup of a MongoDB cluster?<\/p>\n\n\n\n<p>Or some complete misunderstanding.<\/p>\n\n\n\n<p>Anyway, I have meeting in the next hour or two with the project team; let us find out.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>That message from my Manager I got a message from my manager unexpectedly. \u201cHey. A team is converting a MSSQL database to MongoDB.&nbsp; Can Qlik Replicate&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":1720,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[103,16],"tags":[104,36],"class_list":["post-1719","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-mongodb","category-qlik-replicate","tag-mongodb","tag-qlikreplicate"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts\/1719","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1719"}],"version-history":[{"count":7,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts\/1719\/revisions"}],"predecessor-version":[{"id":1729,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts\/1719\/revisions\/1729"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/media\/1720"}],"wp:attachment":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1719"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1719"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1719"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}