76

I've installed MongoDB v4.0 for the most amazing feature of it Transaction in Nodejs with mongodb 3.1 as a driver.

When I try to use a transaction session I've faced this error:

MongoError: Transaction numbers are only allowed on a replica set member or mongos.

What's that and how can I get rid of it?

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
jafar shemshadi
  • 863
  • 1
  • 6
  • 6

10 Answers10

67

Transactions are undoubtedly the most exciting new feature in MongoDB 4.0. But unfortunately, most tools for installing and running MongoDB start a standalone server as opposed to a replica set. If you try to start a session on a standalone server, you'll get this error.

In order to use transactions, you need a MongoDB replica set, and starting a replica set locally for development is an involved process. The new run-rs npm module makes starting replica sets easy. Running run-rs is all you need to start a replica set, run-rs will even install the correct version of MongoDB for you.

Run-rs has no outside dependencies except Node.js and npm. You do not need to have Docker, homebrew, APT, Python, or even MongoDB installed.

Install run-rs globally with npm's -g flag. You can also list run-rs in your package.json file's devDependencies.

npm install run-rs -g

Next, run run-rs with the --version flag. Run-rs will download MongoDB v4.0.0 for you. Don't worry, it won't overwrite your existing MongoDB install.

run-rs -v 4.0.0 --shell

Then use replicaSet=rs in your connection string.

You find more details about it here.

Majid Parvin
  • 4,499
  • 5
  • 29
  • 47
  • 1
    Also useful is the bitnami/mongodb docker image, which allows you to setup a replicaSet with docker-compose: https://github.com/bitnami/bitnami-docker-mongodb#setting-up-a-replication – mltsy Feb 04 '19 at 18:35
  • 8
    From the doc, it seems running an existing (or a new) `mongod` instance with replica-set is rather trivial : https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/ – Marcel Falliere Feb 18 '19 at 12:53
  • 11
    Any idea why the ability to use transactions required MongoDB replica set ? (In my case I have MongoDb instance that run on docker for tests and cannot run transactions due this following this limitation) – Yohan Mar 26 '20 at 22:05
  • runnning into the same limitation as well. Tried using mongodb-memory-server but i think I just dont understand replicaSets well. – dondrzzy Aug 22 '20 at 21:18
  • 1
    Any idea why it needs to be installed globally and not just as a dev dependency? – philosopher Oct 29 '20 at 18:39
  • 1
    Please tell me that, is replica set required while hosting mongodb on cloud too or not...?? – Tayyab Ferozi Dec 22 '20 at 16:30
  • Addition to this answer I also had to apply answer in https://stackoverflow.com/a/62729445/5549301 – Udara Seneviratne Jun 20 '21 at 07:12
  • 5
    Why is replica set required? It makes no sense to me and seems this was a blunder on the mongodb team. – java-addict301 Dec 01 '21 at 18:18
  • 2
    @MarcelFalliere It looks so trivial but it's designed in such way that implementing it in Docker is going to be painful. And it seems from another answer they already broke one Docker solution. Maybe they hate Docker, hate transactions or lure us to use replicas? It makes no sense and goes against whatever principles we created so far... – Gherman Jul 19 '22 at 23:11
  • I got 'Could not connect to any servers in your MongoDB Atlas cluster. One common reason is that you're trying to access the database from an IP that isn't whitelisted.' I thought this was to set a local mongo db to a replica set? – Dashiell Rose Bark-Huss Nov 08 '22 at 05:55
  • Does this help with jest? https://github.com/shelfio/jest-mongodb – OneCricketeer Dec 24 '22 at 01:48
  • Be very careful here, running `run-rs` in a non empty folder can delete or override your files. I had a data folder and it removes all my files from it. – ElJackiste Mar 23 '23 at 17:54
30

I got the solution, and it's just three lines configuration inside the MongoDB config file.

After switching from MongoDB atlas and installing MongoDB v 4.4.0 on my CentOS 7 VPS with WHM, I faced that issue also.

the run-rs solution does not work for me, but I managed to solve this issue without any third-party tool, following these steps:

1. turn off mongod.

the most efficient way is by entering the MongoDB shell with the command mongo checkout the method

db.shutdownServer()

You will be no ability to use the MongoDB server. For me, the shutdown process took too long, and then I killed the process with the command:

systemctl stop -f mongod

if you killed the mongod process,s probably you will need to run mongod --dbpath /var/db --repair

The var/db should point to your database directory.

2. setting replicaSet configuration.

for the replicaSet settings step, check out the /etc/mongod.conf file, look for the replication value line, and you should add the following lines as below:

replication:
   oplogSizeMB: <int>
   replSetName: <string>
   enableMajorityReadConcern: <boolean>

use the replSetName value on the next step.

an example of those settings:

   oplogSizeMB: 2000
   replSetName: rs0
   enableMajorityReadConcern: false

3. add your connection string URL.

add the value of replSetName to your connection URL &replicaSet=--YourReplicationSetName--

if you used the name rs0 from our example, then you should add to your DB connection URL query replicaSet=rs0

4. turn on mongod again

enter the command: systemctl start mongod

5. Access your replicaSet database

enter MongoDB shell with the command mongo, enter the command rs.initiate() now you should be in your replicaSet database.

Oren Hahiashvili
  • 340
  • 1
  • 4
  • 6
  • 2
    Best solution for local development in my opinion. It's really easy to do and works without any third-party software. – Nick Aug 04 '21 at 07:43
  • What value we need to give on replSetName? can you say some example – Kannan T Jan 03 '22 at 13:29
  • Hi @KannanT, I modified my answer and attached an example. – Oren Hahiashvili Jan 04 '22 at 21:00
  • 1
    In case your Mongo Service cannot start after restart, follow https://askubuntu.com/questions/884541/cant-start-mongodb-service – Airy Feb 16 '22 at 11:22
  • If using MongoDB version 5 and above, exclude the `enableMajorityReadConcern: true` line for the `/etc/mongod.conf` file. Check your Mongo installation version with `mongo --version` – Looi May 21 '22 at 10:44
  • Link to the relevant docs: https://www.mongodb.com/docs/manual/reference/configuration-options/#replication-options – Jamie Syme Feb 01 '23 at 17:00
  • In order to connect to the db after the above steps I had to set `directConnection` option in the connection string to `true`: `&directConnection=true` – omercotkd Apr 10 '23 at 15:42
18

For those who wants to develop against of the dockerized MongoDB instance, here is the single-file docker-compose.yaml solution based on the official MongoDB docker image:

version: '3.9'

services:
  mongodb:
    image: mongo:5
    command: --replSet rs0
    ports:
      - "28017:27017"
    environment:
      MONGO_INITDB_DATABASE: attachment-api-local-dev
    healthcheck:
      test: echo 'db.runCommand("ping").ok' | mongo localhost:27017/admin --quiet
      interval: 2s
      timeout: 3s
      retries: 5

  mongo-init:
    image: mongo:5
    restart: "no"
    depends_on:
      mongodb:
        condition: service_healthy
    command: >
      mongo --host mongodb:27017 --eval
      '
      rs.initiate( {
         _id : "rs0",
         members: [
            { _id: 0, host: "localhost:27017" }
         ]
      })
      '

A much easier solution is to just use Bitnami MongoDB image:

services:
  mongodb:
    image: bitnami/mongodb:5.0
    ports:
      - "27017:27017"
    environment:
      MONGODB_REPLICA_SET_MODE: primary
      ALLOW_EMPTY_PASSWORD: 'yes'
Kirill
  • 6,762
  • 4
  • 51
  • 81
  • Apparently, the `MONGODB_REPLICA_SET_KEY` environment variable is also required. Without it, the Mongo process refused to start in the container with an error indicating the variable is mandatory. I just set it to something like `MONGODB_REPLICA_SET_KEY: 123456` – Boaz Dec 13 '22 at 17:52
  • @Boaz never had such a problem with Mongo 5. You probably use 6+ – Kirill Dec 13 '22 at 18:00
  • 1
    Actually, I use 4.2 :) – Boaz Dec 14 '22 at 15:02
13

Possible solution for local development using docker

Create Dockerfile

FROM mongo:4.4.7
RUN echo "rs.initiate();" > /docker-entrypoint-initdb.d/replica-init.js
CMD [ "--replSet", "rs" ]

Build this Dockerfile

docker build ./ -t mongodb:4.7-replset

Run this created image

docker run --name mongodb-replset -p 27017:27017 -d mongodb:4.7-replset

Connect to database using this URI

mongodb://localhost:27017/myDB
Syao May
  • 369
  • 3
  • 4
  • 1
    The suggested solution does not work for MongoDB 5.0.5 because of "MongoServerError: command replSetInitiate requires authentication" (docker-entrypoint.sh does not invoke `mongo` with user and password, also it does not print the error, you can only see it if `mongo` is replaced with `mongosh`). Aside from that you need `CMD ["--replSet", "rs", "--keyFile", "/etc/mongodb.key"]` – Dmitry Mugtasimov Jan 03 '22 at 17:56
  • Even with this work around `RUN echo 'rs.initiate();' > /docker-entrypoint-initdb.d/replica-init.script RUN echo 'mongosh -u "$MONGO_INITDB_ROOT_USERNAME" -p "$MONGO_INITDB_ROOT_PASSWORD" < /docker-entrypoint-initdb.d/replica-init.script' > /docker-entrypoint-initdb.d/replica-init.sh ` we get `MongoServerError: This node was not started with the replSet option`. It is simply because `docker-entrypoint.sh` is not designed to run replicas. Actually, it looks like it is designed not to run them. See `# remove "--auth" and "--replSet" for our initial startup` in the source code – Dmitry Mugtasimov Jan 03 '22 at 18:16
  • Here is related breaking change: https://github.com/docker-library/mongo/issues/211#issuecomment-344347819 – Dmitry Mugtasimov Jan 04 '22 at 01:45
  • If anyone interested see scripts/docker-entrypoint.sh.patch and Dockerfile in https://github.com/thenewboston-developers/Node/pull/69 for workaround/solution – Dmitry Mugtasimov Jan 05 '22 at 18:10
8

I faced the same issue recently. In my case it's because I'm connecting to a remote Mongo server with a different version than my local development environment.

To quickly solve the issue, I added the following param to my connection string:

?retryWrites=false

Ricky
  • 2,912
  • 8
  • 47
  • 74
  • 5
    This looks rather suspicious. Are you sure it doesn't just make all errors silent instead of fixing them? Why is it supposed to work? – Gherman Jul 19 '22 at 23:14
6

When running MongoDB on a Linux Machine, you can simply use replication by updating connection string via editing service file

/usr/lib/mongod.service   or   /lib/systemd/system/mongod.service

and update it with following

ExecStart=/usr/bin/mongod --config "/etc/mongod.conf" --replSet rs0

where --config "/etc/mongod.conf" is pointing to your MongoDB Configuration file and --replSet rs0 is telling it to use replication with the name of rs0

and then restart

sudo systemctl daemon-reload     //<--To reload service units
sudo systemctl restart mongod    //<--To Restart MongoDB Server

and then initiate replication through your mongod instance in terminal

$ mongosh
$ rs.initiate()
Airy
  • 5,484
  • 7
  • 53
  • 78
  • 1
    This was the only that work for me. I have a little question, if I start a connection with mongoose like this: mongodb://localhost:27017/database_name do I need to add something relate with replicaSet. I mean, I've started to make some test and this works perfect only with this without replicaSet in the URL, but I don't know if this could cause problems later. – Luis May 14 '23 at 23:35
  • @Luis It would be better if you tell mongoose or any other connection by including `?replicaSet=rs0`. Whenever I connect through PHP or any other connection, I always do so. – Airy May 16 '23 at 03:48
  • Something strange happened today. I was presented with the replica set error again (which I had solved a long time ago). I don't know why, but that configuration was deleted. I had to add it back. Is this related to mongo updates? – Luis Jun 24 '23 at 22:05
  • @Luis yes it can be highly related to your Linux auto updates. If you have not configured your update settings then mongodb will probably get updated and so its following files. I have witnessed the same for PHP and Nginx etc – Airy Jun 26 '23 at 06:11
  • 1
    I see. Thanks, dude. – Luis Jun 27 '23 at 00:01
2

In order to use transactions, you need a MongoDB replica set, and starting a replica set locally for development is an involved process.

You can use the run-rs npm module. Zero-config MongoDB runner. Starts a replica set with no non-Node dependencies, not even MongoDB.

Or you can simply create an account in MongoDB Atlas which gives you a limited resource MongoDB cluster and so you can run/test your application.

MongoDB Atlas

Mohammad Rajabloo
  • 2,567
  • 19
  • 20
1

Works for mongo:5.0.5-focal image.

Dockerfile:

FROM mongo:5.0.5-focal AS rs-mongo

# Make MongoDB a replica set to support transactions. Based on https://stackoverflow.com/a/68621185/1952977
RUN apt-get update && apt-get install patch

# How to create scripts/docker-entrypoint.sh.patch
# 1. Download the original file:
#    wget https://github.com/docker-library/mongo/raw/master/5.0/docker-entrypoint.sh
#    ( wget https://github.com/docker-library/mongo/raw/b5c0cd58cb5626fee4d963ce05ba4d9026deb265/5.0/docker-entrypoint.sh )
# 2. Make a copy of it:
#    cp docker-entrypoint.sh docker-entrypoint-patched.sh
# 3. Add required modifications to docker-entrypoint-patched.sh
# 4. Create patch:
#    diff -u docker-entrypoint.sh docker-entrypoint-patched.sh > scripts/docker-entrypoint.sh.patch
# 5. Clean up:
#    rm docker-entrypoint.sh docker-entrypoint-patched.sh
COPY scripts/docker-entrypoint.sh.patch .
RUN patch /usr/local/bin/docker-entrypoint.sh docker-entrypoint.sh.patch
RUN mkdir -p /etc/mongo-key && chown mongodb:mongodb /etc/mongo-key

CMD ["--replSet", "rs", "--keyFile", "/etc/mongo-key/mongodb.key"]

scripts/docker-entrypoint.sh.patch:

--- docker-entrypoint.sh    2022-01-04 15:35:19.594435819 +0300
+++ docker-entrypoint-patched.sh    2022-01-06 10:16:26.285394681 +0300
@@ -288,6 +288,10 @@
    fi

    if [ -n "$shouldPerformInitdb" ]; then
+
+     openssl rand -base64 756 > /etc/mongo-key/mongodb.key
+    chmod 400 /etc/mongo-key/mongodb.key
+
        mongodHackedArgs=( "$@" )
        if _parse_config "$@"; then
            _mongod_hack_ensure_arg_val --config "$tempConfigFile" "${mongodHackedArgs[@]}"
@@ -408,7 +412,14 @@
        set -- "$@" --bind_ip_all
    fi

-   unset "${!MONGO_INITDB_@}"
+  echo 'Initiating replica set'
+  "$@" --logpath "/proc/$$/fd/1" --fork
+  echo 'rs.initiate({"_id":"rs","members":[{"_id":0,"host":"127.0.0.1:27017"}]});' | mongosh -u "$MONGO_INITDB_ROOT_USERNAME" -p "$MONGO_INITDB_ROOT_PASSWORD"
+  "$@" --logpath "/proc/$$/fd/1" --shutdown
+  echo 'Done initiating replica set'
+
+  unset "${!MONGO_INITDB_@}"
+
 fi

 rm -f "$jsonConfigFile" "$tempConfigFile"

docker-compose.yml:

version: '3.9'

services:
  mongo:
    image: rs-mongo:current
    restart: always
    env_file:
      - .env
    ports:
      - 127.0.0.1:27017:27017
    volumes:
      - mongo-db:/data/db
      - mongo-configdb:/data/configdb
      - mongo-key:/etc/mongo-key

volumes:
  mongo-db:
    driver: local
  mongo-configdb:
    driver: local
  mongo-key:
    driver: local

UPDATED: 6th of Jan, 2022

Dmitry Mugtasimov
  • 3,858
  • 2
  • 18
  • 26
0

I've been fighting against this issue for weeks. I let you my conclusion. In order to be able to use transactions on a sharded cluster, you need to run at least MongoDB 4.2 on your cluster. If the cluster is not sharded, from 4.0. I was using a library that has as a sub-dependency mongodb NodeJS driver. This driver from version 3.3.x fails against the sharded MongoDB cluster with version 4.0.4. The solution for me was to update my cluster to 4.2 version.

src: https://www.bmc.com/blogs/mongodb-transactions/

M. Gleria
  • 468
  • 5
  • 14
0

The error is because you are using MongoDB sessions and it is not configured on your system.

run this to install run-rs :-

npm install run-rs -g

run:-

run-rs -v 4.0.0 --shell

You should see the below output. Please be patient since MongoDB 4.0.0 is about 70MB.

$ run-rs -v 4.0.0 --shell
Downloading MongoDB 4.0.0
Copied MongoDB 4.0.0 to '/home/node/lib/node_modules/run-rs/4.0.0'
Purging database...
Running '/home/node/lib/node_modules/run-rs/4.0.0/mongod'
Starting replica set...
Started replica set on "mongodb://localhost:27017,localhost:27018,localhost:27019"
Running mongo shell: /home/node/lib/node_modules/run-rs/4.0.0/mongo
rs:PRIMARY>

You now have a replica set running MongoDB 4.0.0 locally. Run rs.status() to verify the replica set is running.

NOTE:- Your nodejs version should be $gte v3.1.0