Uploaded image for project: 'Node.js Driver'
  1. Node.js Driver
  2. NODE-2531

Can't run aggregate queries on secondary

    • Type: Icon: Bug Bug
    • Resolution: Works as Designed
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 3.5.3
    • Component/s: None
    • Environment:
      Linux Ubuntu 1.6.04.6 LTS running in Docker engine 19.03.8 on MacOS Catalina.
      Not using mongoose, not transpiling.
      Using mongodb NPM package from npm.org, version 3.5.3

      Context:

      We have a replicaset of MongoDB instances running in Docker, with one primary and two secondaries. The Node driver is provided a mongodb URL without readPreference, because we want everything to run on primary by default. However, we want to run some aggregate queries on secondaries where we know the data is frozen in time and will never change anymore.

       

      What we do:

      So we want some aggregate queries, not all, to run on secondaries, by setting the options to { readPreference: 'secondary' } to the aggregate function call.

      Then we check what's going on with mogostat to validate our change, and we see that all queries run on primary, nothing happens on secondaries.

       

      Repro code:

      const MongoClient = require('mongodb').MongoClient;
      
      const url = 'mongodb://MyUser:MyPassword@mongo-rs0-1,mongo-rs0-2,mongo-rs0-3/defaultDb?authSource=admin&replicaSet=rs0';
      const dbName = 'anotherDb';
      
      const sleep = require('util').promisify(setTimeout);
      
      const onCollection = async (collection) => {
          // await collection.find({}, { readPreference: 'secondary' });
          await collection.aggregate([{ $match: {} }], { readPreference: 'secondary' }).toArray();
      };
      
      const main = async () => {
          const client = new MongoClient(url, { useNewUrlParser: true });
      
          await client.connect();
      
          try {
              const db = client.db(dbName);
      
              const collections = await db.listCollections().toArray();
      
              while (true) {
                  const tasks = [];
                  for (const collectionInfo of collections) {
                      if (collectionInfo.name.startsWith('MyCollection')) {
                          tasks.push(onCollection(db.collection(collectionInfo.name)));
                      }
                  }
                  await Promise.all(tasks);
                  await sleep(100);
              }
          } finally {
              client.close();
          }
      };
      
      main();
      

      In the onCollection function, the commented find does run the queries on secondaries. So this makes us think it is not a problem with the Docker / MongoDB / ReplicaSet setup.

      Hereafter is the code run to setup the replicaset, in a specific container that is run just to execute the setup:

      /* globals rs, printjson */
      
      const rsConf = {
          _id: 'rs0',
          members: [
              { _id: 0, host: 'mongo-rs0-1:27017' },
              { _id: 1, host: 'mongo-rs0-2:27017' },
              { _id: 2, host: 'mongo-rs0-3:27017' }
          ]
      };
      
      rs.initiate(rsConf);
      
      printjson(rs.config());
      

      I don't think you need the Dockerfile, docker-compose and the initialization scripts. Anyway, the replicaset runs.

      We have seen many articles saying that having aggregate to run secondaries of a replicaset it possible, but all starts the driver in readPreference secondary. That is not what we want. Also, the documentation says that is a query is run on secondary but there are no secondary available, the query fails. In our case, the query does not fail, it just run on primary.

      Here is the command I run to have mongostat: (because of the Docker network isolations)

      docker-compose exec mongo-rs0-1 mongostat --discover -u MuUser -p MyPassword --authenticationDatabase admin
      

      So the question is: Is it a known issue ? Or is it a known limitation ? What is a correct workaround ?

       

      For what it worth, I've tested to provide the driver a mongodb URL with secondaryPreferred, and change all our queries with { readPreference: 'primary' }, except the ones we want to run on secondaries, with { readPreference: 'secondary' } and we saw activities on queries on secondaries on mongostat, but we are not happy with this because:

      1. It's a hack
      2. No way to guarantee we are mistakenly running some queries on primary when they should

       

      Information: 

      Product Info
      Host OS MacOS Catalina
      Guest OS Ubuntu 16.04.6 LTS
      (based on image mongo:3.6 from dockerhub)
       Docker Docker Desktop: 2.2.0.4 (43472)
      Engine:  19.03.8
       NodeJS driver 3.5.3 

       

      Let me know if you need more information. 

      Thanks for your consideration.

       

            Assignee:
            matt.broadstone@mongodb.com Matt Broadstone
            Reporter:
            srobert@moneytree.jp Sebastien Robert
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: